Răsfoiți Sursa

BSLFX #defines now support expressions

BearishSun 9 ani în urmă
părinte
comite
321f21af1c

+ 3 - 0
Source/BansheeCore/Include/BsShaderImportOptions.h

@@ -18,6 +18,9 @@ namespace BansheeEngine
 		/** Returns a modifiable list of defines that will control shader compilation. */
 		/** Returns a modifiable list of defines that will control shader compilation. */
 		UnorderedMap<String, String>& getDefines() { return mDefines; }
 		UnorderedMap<String, String>& getDefines() { return mDefines; }
 
 
+		/** Returns a modifiable list of defines that will control shader compilation. */
+		const UnorderedMap<String, String>& getDefines() const { return mDefines; }
+
 		/************************************************************************/
 		/************************************************************************/
 		/* 								SERIALIZATION                      		*/
 		/* 								SERIALIZATION                      		*/
 		/************************************************************************/
 		/************************************************************************/

+ 386 - 378
Source/BansheeSL/BsLexerFX.l

@@ -1,379 +1,387 @@
-%{
-#include "BsParserFX.h"
-
-#define YY_USER_ACTION yylloc->first_column = yycolumn + 1; yylloc->first_line = yylineno + 1; yycolumn += (int)yyleng; yylloc->filename = getCurrentFilename(yyextra);
-#define YY_USER_INIT yylineno = 0; yycolumn = 0;
-%}
- 
-%option yylineno reentrant noyywrap nounistd never-interactive warn nodefault bison-bridge bison-locations
-%option outfile="BsLexerFX.c" header-file="BsLexerFX.h"
-%option extra-type="struct tagParseState *"
-
-INTEGER			-?[0-9][0-9]*
-INTEGER_16		0[xX][0-9a-fA-F]+
-FLOAT			[0-9]+\.[0-9]+([eE][+-]?[0-9]+)?[fF]?
-STRING			\"[^"\n]*\"
-IDENTIFIER		[_a-zA-Z][_a-zA-Z0-9]*
-WS				[ \r\n\t]*
-SINGLEWS		[ \r\n\t]
-COMMENT			\/\/[^\n]*
-
-	/* Start conditions */
-%x INCLUDE
-%x CODEBLOCK_HEADER
-%x CODEBLOCK_EQUALS
-%x CODEBLOCK
-%x CODEBLOCK_END
-%x DEFINE_COND
-%x UNDEF_COND
-%x CONDITIONAL_IF
-%x CONDITIONAL_IFN
-%x CONDITIONAL_ELIF
-%x CONDITIONAL_IGNORE
-
-%%
-
-{WS}			{ /* Skip blank */ }
-{INTEGER}       { yylval->intValue = atoi(yytext); return TOKEN_INTEGER; }
-{INTEGER_16}    { yylval->intValue = (int)strtol(yytext, 0, 0); return TOKEN_INTEGER; }
-{FLOAT}			{ yylval->floatValue = (float)atof(yytext); return TOKEN_FLOAT; }
-{STRING}		{ yylval->strValue = mmalloc_strdup(yyextra->memContext, yytext); return TOKEN_STRING; }
-true			{ yylval->intValue = 1; return TOKEN_BOOLEAN; }
-false			{ yylval->intValue = 0; return TOKEN_BOOLEAN; }
-
-	/* Value types */
-
-int				{ yylval->intValue = PT_Int; return TOKEN_INTTYPE; } 
-int2			{ yylval->intValue = PT_Int2; return TOKEN_INT2TYPE; } 
-int3			{ yylval->intValue = PT_Int3; return TOKEN_INT3TYPE; } 
-int4			{ yylval->intValue = PT_Int4; return TOKEN_INT4TYPE; }
-
-float			{ yylval->intValue = PT_Float; return TOKEN_FLOATTYPE; } 
-float2			{ yylval->intValue = PT_Float2; return TOKEN_FLOAT2TYPE; } 
-float3			{ yylval->intValue = PT_Float3; return TOKEN_FLOAT3TYPE; } 
-float4			{ yylval->intValue = PT_Float4; return TOKEN_FLOAT4TYPE; }
-color			{ yylval->intValue = PT_Color; return TOKEN_COLORTYPE; }
-
-mat2x2			{ yylval->intValue = PT_Mat2x2; return TOKEN_MAT2x2TYPE; } 
-mat2x3			{ yylval->intValue = PT_Mat2x3; return TOKEN_MAT2x3TYPE; } 
-mat2x4			{ yylval->intValue = PT_Mat2x4; return TOKEN_MAT2x4TYPE; }
-
-mat3x2			{ yylval->intValue = PT_Mat3x2; return TOKEN_MAT3x2TYPE; } 
-mat3x3			{ yylval->intValue = PT_Mat3x3; return TOKEN_MAT3x3TYPE; } 
-mat3x4			{ yylval->intValue = PT_Mat3x4; return TOKEN_MAT3x4TYPE; }
-
-mat4x2			{ yylval->intValue = PT_Mat4x2; return TOKEN_MAT4x2TYPE; } 
-mat4x3			{ yylval->intValue = PT_Mat4x3; return TOKEN_MAT4x3TYPE; } 
-mat4x4			{ yylval->intValue = PT_Mat4x4; return TOKEN_MAT4x4TYPE; }
-
-Sampler1D		{ yylval->intValue = PT_Sampler1D; return TOKEN_SAMPLER1D; } 
-Sampler2D		{ yylval->intValue = PT_Sampler2D; return TOKEN_SAMPLER2D; } 
-Sampler3D		{ yylval->intValue = PT_Sampler3D; return TOKEN_SAMPLER3D; } 
-SamplerCUBE		{ yylval->intValue = PT_SamplerCUBE; return TOKEN_SAMPLERCUBE; } 
-Sampler2DMS		{ yylval->intValue = PT_Sampler2DMS; return TOKEN_SAMPLER2DMS; }
-
-Texture1D		{ yylval->intValue = PT_Texture1D; return TOKEN_TEXTURE1D; } 
-Texture2D		{ yylval->intValue = PT_Texture2D; return TOKEN_TEXTURE2D; } 
-Texture3D		{ yylval->intValue = PT_Texture3D; return TOKEN_TEXTURE3D; } 
-TextureCUBE		{ yylval->intValue = PT_TextureCUBE; return TOKEN_TEXTURECUBE; } 
-Texture2DMS		{ yylval->intValue = PT_Texture2DMS; return TOKEN_TEXTURE2DMS; }
-
-ByteBuffer		{ yylval->intValue = PT_ByteBuffer; return TOKEN_BYTEBUFFER; } 
-StructBuffer	{ yylval->intValue = PT_StructBuffer; return TOKEN_STRUCTBUFFER; } 
-
-TypedBufferRW	{ yylval->intValue = PT_TypedBufferRW; return TOKEN_RWTYPEDBUFFER; } 
-ByteBufferRW	{ yylval->intValue = PT_ByteBufferRW; return TOKEN_RWBYTEBUFFER; }
-StructBufferRW	{ yylval->intValue = PT_StructBufferRW; return TOKEN_RWSTRUCTBUFFER; } 
-AppendBuffer	{ yylval->intValue = PT_AppendBuffer; return TOKEN_RWAPPENDBUFFER; } 
-ConsumeBuffer	{ yylval->intValue = PT_ConsumeBuffer; return TOKEN_RWCONSUMEBUFFER; }
-
-Block			{ return TOKEN_PARAMSBLOCK; }
-
-	/* Shader keywords */
-Separable		{ return TOKEN_SEPARABLE; }
-Queue			{ return TOKEN_QUEUE; }
-Priority		{ return TOKEN_PRIORITY; }
-Transparent		{ return TOKEN_TRANSPARENT; }
-Technique		{ return TOKEN_TECHNIQUE; }
-Parameters		{ return TOKEN_PARAMETERS; }
-Blocks			{ return TOKEN_BLOCKS; }
-
-	/* Technique keywords */
-Renderer		{ return TOKEN_RENDERER; }
-Language		{ return TOKEN_LANGUAGE; }
-Pass			{ return TOKEN_PASS; }
-
-	/* Pass keywords */
-StencilRef		{ return TOKEN_STENCILREF; }
-
-	/* Rasterizer state keywords */
-Fill			{ return TOKEN_FILLMODE; }
-Cull			{ return TOKEN_CULLMODE; }
-DepthBias		{ return TOKEN_DEPTHBIAS; }
-ScaledDepthBias	{ return TOKEN_SDEPTHBIAS; }
-DepthClip		{ return TOKEN_DEPTHCLIP; }
-Scissor			{ return TOKEN_SCISSOR; }
-Multisample		{ return TOKEN_MULTISAMPLE; }
-AALine			{ return TOKEN_AALINE; }
-
-	/* Depth-stencil state keywords */
-DepthRead			{ return TOKEN_DEPTHREAD; }
-DepthWrite			{ return TOKEN_DEPTHWRITE; }
-CompareFunc			{ return TOKEN_COMPAREFUNC; }
-Stencil				{ return TOKEN_STENCIL; }
-StencilReadMask		{ return TOKEN_STENCILREADMASK; }
-StencilWriteMask	{ return TOKEN_STENCILWRITEMASK; }
-StencilOpFront		{ return TOKEN_STENCILOPFRONT; }
-StencilOpBack		{ return TOKEN_STENCILOPBACK; }
-Fail				{ return TOKEN_FAIL; }
-ZFail				{ return TOKEN_ZFAIL; }
-
-	/* Blend state keywords */
-AlphaToCoverage		{ return TOKEN_ALPHATOCOVERAGE; }
-IndependantBlend	{ return TOKEN_INDEPENDANTBLEND; }
-Target				{ return TOKEN_TARGET; }
-Index				{ return TOKEN_INDEX; }
-Blend				{ return TOKEN_BLEND; }
-Color				{ return TOKEN_COLOR; }
-Alpha				{ return TOKEN_ALPHA; }
-WriteMask			{ return TOKEN_WRITEMASK; }
-Source				{ return TOKEN_SOURCE; }
-Dest				{ return TOKEN_DEST; }
-Op					{ return TOKEN_OP; }
-
-	/* Sampler state keywords */
-AddressMode			{ return TOKEN_ADDRMODE; }
-MinFilter			{ return TOKEN_MINFILTER; }
-MagFilter			{ return TOKEN_MAGFILTER; }
-MipFilter			{ return TOKEN_MIPFILTER; }
-MaxAniso			{ return TOKEN_MAXANISO; }
-MipmapBias			{ return TOKEN_MIPBIAS; }
-MipMin				{ return TOKEN_MIPMIN; }
-MipMax				{ return TOKEN_MIPMAX; }
-BorderColor			{ return TOKEN_BORDERCOLOR; }
-U					{ return TOKEN_U; }
-V					{ return TOKEN_V; }
-W					{ return TOKEN_W; }
-
-	/* Qualifiers */
-auto				{ return TOKEN_AUTO; }
-alias				{ return TOKEN_ALIAS; }
-shared				{ return TOKEN_SHARED; }
-usage				{ return TOKEN_USAGE; }
-
-	/* State values */
-WIRE			{ yylval->intValue = FMV_Wire; return TOKEN_FILLMODEVALUE; }
-SOLID			{ yylval->intValue = FMV_Solid; return TOKEN_FILLMODEVALUE; }
-
-NOCULL			{ yylval->intValue = CMV_None; return TOKEN_CULLMODEVALUE; }
-CW				{ yylval->intValue = CMV_CW; return TOKEN_CULLMODEVALUE; }
-CCW				{ yylval->intValue = CMV_CCW; return TOKEN_CULLMODEVALUE; }
-
-FAIL			{ yylval->intValue = CFV_Fail; return TOKEN_COMPFUNCVALUE; }
-PASS			{ yylval->intValue = CFV_Pass; return TOKEN_COMPFUNCVALUE; }
-LT				{ yylval->intValue = CFV_LT; return TOKEN_COMPFUNCVALUE; }
-LTE				{ yylval->intValue = CFV_LTE; return TOKEN_COMPFUNCVALUE; }
-EQ				{ yylval->intValue = CFV_EQ; return TOKEN_COMPFUNCVALUE; }
-NEQ				{ yylval->intValue = CFV_NEQ; return TOKEN_COMPFUNCVALUE; }
-GTE				{ yylval->intValue = CFV_GTE; return TOKEN_COMPFUNCVALUE; }
-GT				{ yylval->intValue = CFV_GT; return TOKEN_COMPFUNCVALUE; }
-
-KEEP				{ yylval->intValue = OV_Keep; return TOKEN_OPVALUE; }
-ZERO				{ yylval->intValue = OV_Zero; return TOKEN_OPVALUE; }
-REPLACE				{ yylval->intValue = OV_Replace; return TOKEN_OPVALUE; }
-INC					{ yylval->intValue = OV_Incr; return TOKEN_OPVALUE; }
-DEC					{ yylval->intValue = OV_Decr; return TOKEN_OPVALUE; }
-INCWRAP				{ yylval->intValue = OV_IncrWrap; return TOKEN_OPVALUE; }
-DECWRAP				{ yylval->intValue = OV_DecrWrap; return TOKEN_OPVALUE; }
-INV					{ yylval->intValue = OV_Invert; return TOKEN_OPVALUE; }
-ONE					{ yylval->intValue = OV_One; return TOKEN_OPVALUE; }
-DSTRGB				{ yylval->intValue = OV_DestColor; return TOKEN_OPVALUE; }
-SRCRGB				{ yylval->intValue = OV_SrcColor; return TOKEN_OPVALUE; }
-DSTIRGB				{ yylval->intValue = OV_InvDestColor; return TOKEN_OPVALUE; }
-SRCIRGB				{ yylval->intValue = OV_InvSrcColor; return TOKEN_OPVALUE; }
-DSTA				{ yylval->intValue = OV_DestAlpha; return TOKEN_OPVALUE; }
-SRCA				{ yylval->intValue = OV_SrcAlpha; return TOKEN_OPVALUE; }
-DSTIA				{ yylval->intValue = OV_InvDestAlpha; return TOKEN_OPVALUE; }
-SRCIA				{ yylval->intValue = OV_InvSrcAlpha; return TOKEN_OPVALUE; }
-
-ADD					{ yylval->intValue = BOV_Add; return TOKEN_BLENDOPVALUE; }
-SUB					{ yylval->intValue = BOV_Subtract; return TOKEN_BLENDOPVALUE; }
-RSUB				{ yylval->intValue = BOV_RevSubtract; return TOKEN_BLENDOPVALUE; }
-MIN					{ yylval->intValue = BOV_Min; return TOKEN_BLENDOPVALUE; }
-MAX					{ yylval->intValue = BOV_Max; return TOKEN_BLENDOPVALUE; }
-
-NOCOLOR			{ yylval->intValue = 0x0; return TOKEN_COLORMASK; }
-R				{ yylval->intValue = 0x1; return TOKEN_COLORMASK; }
-G				{ yylval->intValue = 0x2; return TOKEN_COLORMASK; }
-B				{ yylval->intValue = 0x4; return TOKEN_COLORMASK; }
-A				{ yylval->intValue = 0x8; return TOKEN_COLORMASK; }
-RG				{ yylval->intValue = 0x3; return TOKEN_COLORMASK; }
-RB				{ yylval->intValue = 0x5; return TOKEN_COLORMASK; }
-RA				{ yylval->intValue = 0x9; return TOKEN_COLORMASK; }
-GB				{ yylval->intValue = 0x6; return TOKEN_COLORMASK; }
-GA				{ yylval->intValue = 0xA; return TOKEN_COLORMASK; }
-BA				{ yylval->intValue = 0xC; return TOKEN_COLORMASK; }
-RGB				{ yylval->intValue = 0x7; return TOKEN_COLORMASK; }
-RGA				{ yylval->intValue = 0xB; return TOKEN_COLORMASK; }
-RBA				{ yylval->intValue = 0xD; return TOKEN_COLORMASK; }
-GBA				{ yylval->intValue = 0xE; return TOKEN_COLORMASK; }
-RGBA			{ yylval->intValue = 0xF; return TOKEN_COLORMASK; }
-
-WRAP			{ yylval->intValue = AMV_Wrap; return TOKEN_ADDRMODEVALUE; }
-MIRROR			{ yylval->intValue = AMV_Mirror; return TOKEN_ADDRMODEVALUE; }
-CLAMP			{ yylval->intValue = AMV_Clamp; return TOKEN_ADDRMODEVALUE; }
-BORDER			{ yylval->intValue = AMV_Border; return TOKEN_ADDRMODEVALUE; }
-
-NOFILTER		{ yylval->intValue = FV_None; return TOKEN_FILTERVALUE; }
-POINT			{ yylval->intValue = FV_Point; return TOKEN_FILTERVALUE; }
-LINEAR			{ yylval->intValue = FV_Linear; return TOKEN_FILTERVALUE; }
-ANISO			{ yylval->intValue = FV_Anisotropic; return TOKEN_FILTERVALUE; }
-POINTC			{ yylval->intValue = FV_PointCmp; return TOKEN_FILTERVALUE; }
-LINEARC			{ yylval->intValue = FV_LinearCmp; return TOKEN_FILTERVALUE; }
-ANISOC			{ yylval->intValue = FV_AnisotropicCmp; return TOKEN_FILTERVALUE; }
-
-STATIC			{ yylval->intValue = BUV_Static; return TOKEN_BUFFERUSAGE; }
-DYNAMIC			{ yylval->intValue = BUV_Dynamic; return TOKEN_BUFFERUSAGE; }
-
-	/* Preprocessor */
-#include				{ BEGIN(INCLUDE); }
-
-<INCLUDE>{WS}			{ /* Skip blank */ }
-<INCLUDE>{STRING}		{
-	int size = 0;
-	char* includeBuffer = includePush(yyextra, yytext, yylineno, yycolumn, &size);
-	if(!includeBuffer)
-		yyterminate();
-
-	YY_BUFFER_STATE currentBuffer = YY_CURRENT_BUFFER;
-	YY_BUFFER_STATE newBuffer = yy_scan_buffer(includeBuffer, size, yyscanner);
-
-	yy_switch_to_buffer(currentBuffer, yyscanner);
-	yypush_buffer_state(newBuffer, yyscanner);
-
-	yylineno = 0; 
-	yycolumn = 0;
-
-	BEGIN(INITIAL);
-	}
-<INCLUDE>.				{ return yytext[0]; }
-
-<<EOF>>					{
-	if(!yyextra->includeStack)
-		yyterminate();
-
-	yypop_buffer_state(yyscanner);
-	includePop(yyextra);
-}
-
-#define							{ BEGIN(DEFINE_COND); }
-<DEFINE_COND>{WS}				{ /* Skip blank */ }
-<DEFINE_COND>{IDENTIFIER}		{ addDefine(yyextra, yytext); BEGIN(INITIAL); }
-<DEFINE_COND>.					{ return yytext[0]; }
-
-#undef							{ BEGIN(UNDEF_COND); }
-<UNDEF_COND>{WS}				{ /* Skip blank */ }
-<UNDEF_COND>{IDENTIFIER}		{ removeDefine(yyextra, yytext); BEGIN(INITIAL); }
-<UNDEF_COND>.					{ return yytext[0]; }
-
-#ifdef							{ BEGIN(CONDITIONAL_IF); }
-<CONDITIONAL_IF>{WS}			{ /* Skip blank */ }
-<CONDITIONAL_IF>{IDENTIFIER}	{ 
-	int isEnabled = pushConditional(yyextra, hasDefine(yyextra, yytext));
-	if(!isEnabled)
-		BEGIN(CONDITIONAL_IGNORE);
-	else
-		BEGIN(INITIAL);
-}
-<CONDITIONAL_IF>.				{ return yytext[0]; }
-
-#ifndef							{ BEGIN(CONDITIONAL_IFN); }
-<CONDITIONAL_IFN>{WS}			{ /* Skip blank */ }
-<CONDITIONAL_IFN>{IDENTIFIER}	{ 
-	int isEnabled = pushConditional(yyextra, !hasDefine(yyextra, yytext));
-	if(!isEnabled)
-		BEGIN(CONDITIONAL_IGNORE);
-	else
-		BEGIN(INITIAL);
-}
-<CONDITIONAL_IFN>.				{ return yytext[0]; }
-
-#else							{ BEGIN(CONDITIONAL_IGNORE); }
-#elif							{ BEGIN(CONDITIONAL_IGNORE); }
-
-#endif							{ popConditional(yyextra); }
-
-<CONDITIONAL_IGNORE>{WS}		{ /* Skip */ }
-<CONDITIONAL_IGNORE>#ifdef		{ pushConditional(yyextra, 0); }
-<CONDITIONAL_IGNORE>#ifndef		{ pushConditional(yyextra, 0); }
-<CONDITIONAL_IGNORE>#else		{ 
-	if(switchConditional(yyextra))
-		BEGIN(INITIAL);
-}
-<CONDITIONAL_IGNORE>#elif		{ BEGIN(CONDITIONAL_ELIF); }
-<CONDITIONAL_IGNORE>#endif		{ 
-	if(popConditional(yyextra))
-		BEGIN(INITIAL);
-}
-<CONDITIONAL_IGNORE>.			{ /* Skip */ }
-
-<CONDITIONAL_ELIF>{WS}			{ /* Skip blank */ }
-<CONDITIONAL_ELIF>{IDENTIFIER}	{ 
-	int isEnabled = setConditional(yyextra, hasDefine(yyextra, yytext));
-	if(!isEnabled)
-		BEGIN(CONDITIONAL_IGNORE);
-	else
-		BEGIN(INITIAL);
-}
-<CONDITIONAL_ELIF>.				{ return yytext[0]; }
-
-	/* Code blocks */
-Vertex			{ BEGIN(CODEBLOCK_HEADER); return TOKEN_VERTEX; }
-Fragment		{ BEGIN(CODEBLOCK_HEADER); return TOKEN_FRAGMENT; }
-Geometry		{ BEGIN(CODEBLOCK_HEADER); return TOKEN_GEOMETRY; }
-Hull			{ BEGIN(CODEBLOCK_HEADER); return TOKEN_HULL; }
-Domain			{ BEGIN(CODEBLOCK_HEADER); return TOKEN_DOMAIN; }
-Compute			{ BEGIN(CODEBLOCK_HEADER); return TOKEN_COMPUTE; }
-Common			{ BEGIN(CODEBLOCK_HEADER); return TOKEN_COMMON; }
-
-	/* Track when the code block begins, insert all code block characters into our own buffer, record a sequential index */
-	/* of all code blocks in the text, and track bracket open/closed state so we know when we're done with the code block. */
-	/* And finally output a sequential code block index to the parser (it shouldn't be aware of anything else in the block). */
-<CODEBLOCK_HEADER>=		{ BEGIN(CODEBLOCK_EQUALS); return yytext[0]; }
-<CODEBLOCK_HEADER>{WS}	{ /* Skip blank */ }
-<CODEBLOCK_HEADER>.		{ return yytext[0]; }
-
-<CODEBLOCK_EQUALS>\{	{ BEGIN(CODEBLOCK); beginCodeBlock(yyextra); yyextra->numOpenBrackets = 1; return yytext[0]; }
-<CODEBLOCK_EQUALS>{WS}	{ /* Skip blank */ }
-<CODEBLOCK_EQUALS>.		{ return yytext[0]; }
-
-<CODEBLOCK>\{			{ yyextra->numOpenBrackets++; appendCodeBlock(yyextra, yytext, 1); }
-<CODEBLOCK>\}			{ 
-	yyextra->numOpenBrackets--; 
-
-	if(yyextra->numOpenBrackets == 0)
-	{
-		BEGIN(CODEBLOCK_END);
-		unput('0');
-	}
-	else
-		appendCodeBlock(yyextra, yytext, 1);
-}
-<CODEBLOCK>.|{SINGLEWS}		{ appendCodeBlock(yyextra, yytext, 1); }
-
-	/* Logic for manually inserting "Index = codeBlockIndex;". We insert arbitrary numbers which allows us to sequentially */
-	/* output all the tokens we need. We use only single-character values so we don't override anything in the text buffer */
-	/* (since the starting value was also a single character "{"). */
-<CODEBLOCK_END>0	{ unput('1'); return TOKEN_INDEX; }
-<CODEBLOCK_END>1	{ unput('2'); return '='; }
-<CODEBLOCK_END>2	{ yylval->intValue = getCodeBlockIndex(yyextra); unput('3'); return TOKEN_INTEGER; }
-<CODEBLOCK_END>3	{ unput('4'); return ';'; }
-<CODEBLOCK_END>4	{ BEGIN(INITIAL); return '}'; }
-<CODEBLOCK_END>.|{WS}	{ /* Never reached */ }
-
-	/* Catch all rules */
-{COMMENT}			{ }
-{IDENTIFIER}		{ yylval->strValue = mmalloc_strdup(yyextra->memContext, yytext); return TOKEN_IDENTIFIER; }
-.					{ return yytext[0]; }
-
+%{
+#include "BsParserFX.h"
+
+#define YY_USER_ACTION yylloc->first_column = yycolumn + 1; yylloc->first_line = yylineno + 1; yycolumn += (int)yyleng; yylloc->filename = getCurrentFilename(yyextra);
+#define YY_USER_INIT yylineno = 0; yycolumn = 0;
+%}
+ 
+%option yylineno reentrant noyywrap nounistd never-interactive warn nodefault bison-bridge bison-locations
+%option outfile="BsLexerFX.c" header-file="BsLexerFX.h"
+%option extra-type="struct tagParseState *"
+
+INTEGER			-?[0-9][0-9]*
+INTEGER_16		0[xX][0-9a-fA-F]+
+FLOAT			[0-9]+\.[0-9]+([eE][+-]?[0-9]+)?[fF]?
+STRING			\"[^"\n]*\"
+IDENTIFIER		[_a-zA-Z][_a-zA-Z0-9]*
+WS				[ \r\n\t]*
+SINGLEWS		[ \r\n\t]
+ENDLINE			[\r\n]
+COMMENT			\/\/[^\n]*
+DEFINE_EXPR		[^\r\n]*
+
+	/* Start conditions */
+%x INCLUDE
+%x CODEBLOCK_HEADER
+%x CODEBLOCK_EQUALS
+%x CODEBLOCK
+%x CODEBLOCK_END
+%x DEFINE_COND
+%x DEFINE_COND_EXPR
+%x UNDEF_COND
+%x CONDITIONAL_IF
+%x CONDITIONAL_IFN
+%x CONDITIONAL_ELIF
+%x CONDITIONAL_IGNORE
+
+%%
+
+{WS}			{ /* Skip blank */ }
+{INTEGER}       { yylval->intValue = atoi(yytext); return TOKEN_INTEGER; }
+{INTEGER_16}    { yylval->intValue = (int)strtol(yytext, 0, 0); return TOKEN_INTEGER; }
+{FLOAT}			{ yylval->floatValue = (float)atof(yytext); return TOKEN_FLOAT; }
+{STRING}		{ yylval->strValue = mmalloc_strdup(yyextra->memContext, yytext); return TOKEN_STRING; }
+true			{ yylval->intValue = 1; return TOKEN_BOOLEAN; }
+false			{ yylval->intValue = 0; return TOKEN_BOOLEAN; }
+
+	/* Value types */
+
+int				{ yylval->intValue = PT_Int; return TOKEN_INTTYPE; } 
+int2			{ yylval->intValue = PT_Int2; return TOKEN_INT2TYPE; } 
+int3			{ yylval->intValue = PT_Int3; return TOKEN_INT3TYPE; } 
+int4			{ yylval->intValue = PT_Int4; return TOKEN_INT4TYPE; }
+
+float			{ yylval->intValue = PT_Float; return TOKEN_FLOATTYPE; } 
+float2			{ yylval->intValue = PT_Float2; return TOKEN_FLOAT2TYPE; } 
+float3			{ yylval->intValue = PT_Float3; return TOKEN_FLOAT3TYPE; } 
+float4			{ yylval->intValue = PT_Float4; return TOKEN_FLOAT4TYPE; }
+color			{ yylval->intValue = PT_Color; return TOKEN_COLORTYPE; }
+
+mat2x2			{ yylval->intValue = PT_Mat2x2; return TOKEN_MAT2x2TYPE; } 
+mat2x3			{ yylval->intValue = PT_Mat2x3; return TOKEN_MAT2x3TYPE; } 
+mat2x4			{ yylval->intValue = PT_Mat2x4; return TOKEN_MAT2x4TYPE; }
+
+mat3x2			{ yylval->intValue = PT_Mat3x2; return TOKEN_MAT3x2TYPE; } 
+mat3x3			{ yylval->intValue = PT_Mat3x3; return TOKEN_MAT3x3TYPE; } 
+mat3x4			{ yylval->intValue = PT_Mat3x4; return TOKEN_MAT3x4TYPE; }
+
+mat4x2			{ yylval->intValue = PT_Mat4x2; return TOKEN_MAT4x2TYPE; } 
+mat4x3			{ yylval->intValue = PT_Mat4x3; return TOKEN_MAT4x3TYPE; } 
+mat4x4			{ yylval->intValue = PT_Mat4x4; return TOKEN_MAT4x4TYPE; }
+
+Sampler1D		{ yylval->intValue = PT_Sampler1D; return TOKEN_SAMPLER1D; } 
+Sampler2D		{ yylval->intValue = PT_Sampler2D; return TOKEN_SAMPLER2D; } 
+Sampler3D		{ yylval->intValue = PT_Sampler3D; return TOKEN_SAMPLER3D; } 
+SamplerCUBE		{ yylval->intValue = PT_SamplerCUBE; return TOKEN_SAMPLERCUBE; } 
+Sampler2DMS		{ yylval->intValue = PT_Sampler2DMS; return TOKEN_SAMPLER2DMS; }
+
+Texture1D		{ yylval->intValue = PT_Texture1D; return TOKEN_TEXTURE1D; } 
+Texture2D		{ yylval->intValue = PT_Texture2D; return TOKEN_TEXTURE2D; } 
+Texture3D		{ yylval->intValue = PT_Texture3D; return TOKEN_TEXTURE3D; } 
+TextureCUBE		{ yylval->intValue = PT_TextureCUBE; return TOKEN_TEXTURECUBE; } 
+Texture2DMS		{ yylval->intValue = PT_Texture2DMS; return TOKEN_TEXTURE2DMS; }
+
+ByteBuffer		{ yylval->intValue = PT_ByteBuffer; return TOKEN_BYTEBUFFER; } 
+StructBuffer	{ yylval->intValue = PT_StructBuffer; return TOKEN_STRUCTBUFFER; } 
+
+TypedBufferRW	{ yylval->intValue = PT_TypedBufferRW; return TOKEN_RWTYPEDBUFFER; } 
+ByteBufferRW	{ yylval->intValue = PT_ByteBufferRW; return TOKEN_RWBYTEBUFFER; }
+StructBufferRW	{ yylval->intValue = PT_StructBufferRW; return TOKEN_RWSTRUCTBUFFER; } 
+AppendBuffer	{ yylval->intValue = PT_AppendBuffer; return TOKEN_RWAPPENDBUFFER; } 
+ConsumeBuffer	{ yylval->intValue = PT_ConsumeBuffer; return TOKEN_RWCONSUMEBUFFER; }
+
+Block			{ return TOKEN_PARAMSBLOCK; }
+
+	/* Shader keywords */
+Separable		{ return TOKEN_SEPARABLE; }
+Queue			{ return TOKEN_QUEUE; }
+Priority		{ return TOKEN_PRIORITY; }
+Transparent		{ return TOKEN_TRANSPARENT; }
+Technique		{ return TOKEN_TECHNIQUE; }
+Parameters		{ return TOKEN_PARAMETERS; }
+Blocks			{ return TOKEN_BLOCKS; }
+
+	/* Technique keywords */
+Renderer		{ return TOKEN_RENDERER; }
+Language		{ return TOKEN_LANGUAGE; }
+Pass			{ return TOKEN_PASS; }
+
+	/* Pass keywords */
+StencilRef		{ return TOKEN_STENCILREF; }
+
+	/* Rasterizer state keywords */
+Fill			{ return TOKEN_FILLMODE; }
+Cull			{ return TOKEN_CULLMODE; }
+DepthBias		{ return TOKEN_DEPTHBIAS; }
+ScaledDepthBias	{ return TOKEN_SDEPTHBIAS; }
+DepthClip		{ return TOKEN_DEPTHCLIP; }
+Scissor			{ return TOKEN_SCISSOR; }
+Multisample		{ return TOKEN_MULTISAMPLE; }
+AALine			{ return TOKEN_AALINE; }
+
+	/* Depth-stencil state keywords */
+DepthRead			{ return TOKEN_DEPTHREAD; }
+DepthWrite			{ return TOKEN_DEPTHWRITE; }
+CompareFunc			{ return TOKEN_COMPAREFUNC; }
+Stencil				{ return TOKEN_STENCIL; }
+StencilReadMask		{ return TOKEN_STENCILREADMASK; }
+StencilWriteMask	{ return TOKEN_STENCILWRITEMASK; }
+StencilOpFront		{ return TOKEN_STENCILOPFRONT; }
+StencilOpBack		{ return TOKEN_STENCILOPBACK; }
+Fail				{ return TOKEN_FAIL; }
+ZFail				{ return TOKEN_ZFAIL; }
+
+	/* Blend state keywords */
+AlphaToCoverage		{ return TOKEN_ALPHATOCOVERAGE; }
+IndependantBlend	{ return TOKEN_INDEPENDANTBLEND; }
+Target				{ return TOKEN_TARGET; }
+Index				{ return TOKEN_INDEX; }
+Blend				{ return TOKEN_BLEND; }
+Color				{ return TOKEN_COLOR; }
+Alpha				{ return TOKEN_ALPHA; }
+WriteMask			{ return TOKEN_WRITEMASK; }
+Source				{ return TOKEN_SOURCE; }
+Dest				{ return TOKEN_DEST; }
+Op					{ return TOKEN_OP; }
+
+	/* Sampler state keywords */
+AddressMode			{ return TOKEN_ADDRMODE; }
+MinFilter			{ return TOKEN_MINFILTER; }
+MagFilter			{ return TOKEN_MAGFILTER; }
+MipFilter			{ return TOKEN_MIPFILTER; }
+MaxAniso			{ return TOKEN_MAXANISO; }
+MipmapBias			{ return TOKEN_MIPBIAS; }
+MipMin				{ return TOKEN_MIPMIN; }
+MipMax				{ return TOKEN_MIPMAX; }
+BorderColor			{ return TOKEN_BORDERCOLOR; }
+U					{ return TOKEN_U; }
+V					{ return TOKEN_V; }
+W					{ return TOKEN_W; }
+
+	/* Qualifiers */
+auto				{ return TOKEN_AUTO; }
+alias				{ return TOKEN_ALIAS; }
+shared				{ return TOKEN_SHARED; }
+usage				{ return TOKEN_USAGE; }
+
+	/* State values */
+WIRE			{ yylval->intValue = FMV_Wire; return TOKEN_FILLMODEVALUE; }
+SOLID			{ yylval->intValue = FMV_Solid; return TOKEN_FILLMODEVALUE; }
+
+NOCULL			{ yylval->intValue = CMV_None; return TOKEN_CULLMODEVALUE; }
+CW				{ yylval->intValue = CMV_CW; return TOKEN_CULLMODEVALUE; }
+CCW				{ yylval->intValue = CMV_CCW; return TOKEN_CULLMODEVALUE; }
+
+FAIL			{ yylval->intValue = CFV_Fail; return TOKEN_COMPFUNCVALUE; }
+PASS			{ yylval->intValue = CFV_Pass; return TOKEN_COMPFUNCVALUE; }
+LT				{ yylval->intValue = CFV_LT; return TOKEN_COMPFUNCVALUE; }
+LTE				{ yylval->intValue = CFV_LTE; return TOKEN_COMPFUNCVALUE; }
+EQ				{ yylval->intValue = CFV_EQ; return TOKEN_COMPFUNCVALUE; }
+NEQ				{ yylval->intValue = CFV_NEQ; return TOKEN_COMPFUNCVALUE; }
+GTE				{ yylval->intValue = CFV_GTE; return TOKEN_COMPFUNCVALUE; }
+GT				{ yylval->intValue = CFV_GT; return TOKEN_COMPFUNCVALUE; }
+
+KEEP				{ yylval->intValue = OV_Keep; return TOKEN_OPVALUE; }
+ZERO				{ yylval->intValue = OV_Zero; return TOKEN_OPVALUE; }
+REPLACE				{ yylval->intValue = OV_Replace; return TOKEN_OPVALUE; }
+INC					{ yylval->intValue = OV_Incr; return TOKEN_OPVALUE; }
+DEC					{ yylval->intValue = OV_Decr; return TOKEN_OPVALUE; }
+INCWRAP				{ yylval->intValue = OV_IncrWrap; return TOKEN_OPVALUE; }
+DECWRAP				{ yylval->intValue = OV_DecrWrap; return TOKEN_OPVALUE; }
+INV					{ yylval->intValue = OV_Invert; return TOKEN_OPVALUE; }
+ONE					{ yylval->intValue = OV_One; return TOKEN_OPVALUE; }
+DSTRGB				{ yylval->intValue = OV_DestColor; return TOKEN_OPVALUE; }
+SRCRGB				{ yylval->intValue = OV_SrcColor; return TOKEN_OPVALUE; }
+DSTIRGB				{ yylval->intValue = OV_InvDestColor; return TOKEN_OPVALUE; }
+SRCIRGB				{ yylval->intValue = OV_InvSrcColor; return TOKEN_OPVALUE; }
+DSTA				{ yylval->intValue = OV_DestAlpha; return TOKEN_OPVALUE; }
+SRCA				{ yylval->intValue = OV_SrcAlpha; return TOKEN_OPVALUE; }
+DSTIA				{ yylval->intValue = OV_InvDestAlpha; return TOKEN_OPVALUE; }
+SRCIA				{ yylval->intValue = OV_InvSrcAlpha; return TOKEN_OPVALUE; }
+
+ADD					{ yylval->intValue = BOV_Add; return TOKEN_BLENDOPVALUE; }
+SUB					{ yylval->intValue = BOV_Subtract; return TOKEN_BLENDOPVALUE; }
+RSUB				{ yylval->intValue = BOV_RevSubtract; return TOKEN_BLENDOPVALUE; }
+MIN					{ yylval->intValue = BOV_Min; return TOKEN_BLENDOPVALUE; }
+MAX					{ yylval->intValue = BOV_Max; return TOKEN_BLENDOPVALUE; }
+
+NOCOLOR			{ yylval->intValue = 0x0; return TOKEN_COLORMASK; }
+R				{ yylval->intValue = 0x1; return TOKEN_COLORMASK; }
+G				{ yylval->intValue = 0x2; return TOKEN_COLORMASK; }
+B				{ yylval->intValue = 0x4; return TOKEN_COLORMASK; }
+A				{ yylval->intValue = 0x8; return TOKEN_COLORMASK; }
+RG				{ yylval->intValue = 0x3; return TOKEN_COLORMASK; }
+RB				{ yylval->intValue = 0x5; return TOKEN_COLORMASK; }
+RA				{ yylval->intValue = 0x9; return TOKEN_COLORMASK; }
+GB				{ yylval->intValue = 0x6; return TOKEN_COLORMASK; }
+GA				{ yylval->intValue = 0xA; return TOKEN_COLORMASK; }
+BA				{ yylval->intValue = 0xC; return TOKEN_COLORMASK; }
+RGB				{ yylval->intValue = 0x7; return TOKEN_COLORMASK; }
+RGA				{ yylval->intValue = 0xB; return TOKEN_COLORMASK; }
+RBA				{ yylval->intValue = 0xD; return TOKEN_COLORMASK; }
+GBA				{ yylval->intValue = 0xE; return TOKEN_COLORMASK; }
+RGBA			{ yylval->intValue = 0xF; return TOKEN_COLORMASK; }
+
+WRAP			{ yylval->intValue = AMV_Wrap; return TOKEN_ADDRMODEVALUE; }
+MIRROR			{ yylval->intValue = AMV_Mirror; return TOKEN_ADDRMODEVALUE; }
+CLAMP			{ yylval->intValue = AMV_Clamp; return TOKEN_ADDRMODEVALUE; }
+BORDER			{ yylval->intValue = AMV_Border; return TOKEN_ADDRMODEVALUE; }
+
+NOFILTER		{ yylval->intValue = FV_None; return TOKEN_FILTERVALUE; }
+POINT			{ yylval->intValue = FV_Point; return TOKEN_FILTERVALUE; }
+LINEAR			{ yylval->intValue = FV_Linear; return TOKEN_FILTERVALUE; }
+ANISO			{ yylval->intValue = FV_Anisotropic; return TOKEN_FILTERVALUE; }
+POINTC			{ yylval->intValue = FV_PointCmp; return TOKEN_FILTERVALUE; }
+LINEARC			{ yylval->intValue = FV_LinearCmp; return TOKEN_FILTERVALUE; }
+ANISOC			{ yylval->intValue = FV_AnisotropicCmp; return TOKEN_FILTERVALUE; }
+
+STATIC			{ yylval->intValue = BUV_Static; return TOKEN_BUFFERUSAGE; }
+DYNAMIC			{ yylval->intValue = BUV_Dynamic; return TOKEN_BUFFERUSAGE; }
+
+	/* Preprocessor */
+#include				{ BEGIN(INCLUDE); }
+
+<INCLUDE>{WS}			{ /* Skip blank */ }
+<INCLUDE>{STRING}		{
+	int size = 0;
+	char* includeBuffer = includePush(yyextra, yytext, yylineno, yycolumn, &size);
+	if(!includeBuffer)
+		yyterminate();
+
+	YY_BUFFER_STATE currentBuffer = YY_CURRENT_BUFFER;
+	YY_BUFFER_STATE newBuffer = yy_scan_buffer(includeBuffer, size, yyscanner);
+
+	yy_switch_to_buffer(currentBuffer, yyscanner);
+	yypush_buffer_state(newBuffer, yyscanner);
+
+	yylineno = 0; 
+	yycolumn = 0;
+
+	BEGIN(INITIAL);
+	}
+<INCLUDE>.				{ return yytext[0]; }
+
+<<EOF>>					{
+	if(!yyextra->includeStack)
+		yyterminate();
+
+	yypop_buffer_state(yyscanner);
+	includePop(yyextra);
+}
+
+#define							{ BEGIN(DEFINE_COND); }
+<DEFINE_COND>{WS}				{ /* Skip blank */ }
+<DEFINE_COND>{IDENTIFIER}		{ addDefine(yyextra, yytext); BEGIN(DEFINE_COND_EXPR); }
+<DEFINE_COND>{ENDLINE}			{ BEGIN(INITIAL); }
+<DEFINE_COND>.					{ return yytext[0]; }
+
+<DEFINE_COND_EXPR>{DEFINE_EXPR}		{ addDefineExpr(yyextra, yytext); BEGIN(INITIAL); }
+<DEFINE_COND_EXPR>{ENDLINE}			{ BEGIN(INITIAL); }
+<DEFINE_COND_EXPR>.					{ return yytext[0]; }
+
+#undef							{ BEGIN(UNDEF_COND); }
+<UNDEF_COND>{WS}				{ /* Skip blank */ }
+<UNDEF_COND>{IDENTIFIER}		{ removeDefine(yyextra, yytext); BEGIN(INITIAL); }
+<UNDEF_COND>.					{ return yytext[0]; }
+
+#ifdef							{ BEGIN(CONDITIONAL_IF); }
+<CONDITIONAL_IF>{WS}			{ /* Skip blank */ }
+<CONDITIONAL_IF>{IDENTIFIER}	{ 
+	int isEnabled = pushConditional(yyextra, hasDefine(yyextra, yytext));
+	if(!isEnabled)
+		BEGIN(CONDITIONAL_IGNORE);
+	else
+		BEGIN(INITIAL);
+}
+<CONDITIONAL_IF>.				{ return yytext[0]; }
+
+#ifndef							{ BEGIN(CONDITIONAL_IFN); }
+<CONDITIONAL_IFN>{WS}			{ /* Skip blank */ }
+<CONDITIONAL_IFN>{IDENTIFIER}	{ 
+	int isEnabled = pushConditional(yyextra, !hasDefine(yyextra, yytext));
+	if(!isEnabled)
+		BEGIN(CONDITIONAL_IGNORE);
+	else
+		BEGIN(INITIAL);
+}
+<CONDITIONAL_IFN>.				{ return yytext[0]; }
+
+#else							{ BEGIN(CONDITIONAL_IGNORE); }
+#elif							{ BEGIN(CONDITIONAL_IGNORE); }
+
+#endif							{ popConditional(yyextra); }
+
+<CONDITIONAL_IGNORE>{WS}		{ /* Skip */ }
+<CONDITIONAL_IGNORE>#ifdef		{ pushConditional(yyextra, 0); }
+<CONDITIONAL_IGNORE>#ifndef		{ pushConditional(yyextra, 0); }
+<CONDITIONAL_IGNORE>#else		{ 
+	if(switchConditional(yyextra))
+		BEGIN(INITIAL);
+}
+<CONDITIONAL_IGNORE>#elif		{ BEGIN(CONDITIONAL_ELIF); }
+<CONDITIONAL_IGNORE>#endif		{ 
+	if(popConditional(yyextra))
+		BEGIN(INITIAL);
+}
+<CONDITIONAL_IGNORE>.			{ /* Skip */ }
+
+<CONDITIONAL_ELIF>{WS}			{ /* Skip blank */ }
+<CONDITIONAL_ELIF>{IDENTIFIER}	{ 
+	int isEnabled = setConditional(yyextra, hasDefine(yyextra, yytext));
+	if(!isEnabled)
+		BEGIN(CONDITIONAL_IGNORE);
+	else
+		BEGIN(INITIAL);
+}
+<CONDITIONAL_ELIF>.				{ return yytext[0]; }
+
+	/* Code blocks */
+Vertex			{ BEGIN(CODEBLOCK_HEADER); return TOKEN_VERTEX; }
+Fragment		{ BEGIN(CODEBLOCK_HEADER); return TOKEN_FRAGMENT; }
+Geometry		{ BEGIN(CODEBLOCK_HEADER); return TOKEN_GEOMETRY; }
+Hull			{ BEGIN(CODEBLOCK_HEADER); return TOKEN_HULL; }
+Domain			{ BEGIN(CODEBLOCK_HEADER); return TOKEN_DOMAIN; }
+Compute			{ BEGIN(CODEBLOCK_HEADER); return TOKEN_COMPUTE; }
+Common			{ BEGIN(CODEBLOCK_HEADER); return TOKEN_COMMON; }
+
+	/* Track when the code block begins, insert all code block characters into our own buffer, record a sequential index */
+	/* of all code blocks in the text, and track bracket open/closed state so we know when we're done with the code block. */
+	/* And finally output a sequential code block index to the parser (it shouldn't be aware of anything else in the block). */
+<CODEBLOCK_HEADER>=		{ BEGIN(CODEBLOCK_EQUALS); return yytext[0]; }
+<CODEBLOCK_HEADER>{WS}	{ /* Skip blank */ }
+<CODEBLOCK_HEADER>.		{ return yytext[0]; }
+
+<CODEBLOCK_EQUALS>\{	{ BEGIN(CODEBLOCK); beginCodeBlock(yyextra); yyextra->numOpenBrackets = 1; return yytext[0]; }
+<CODEBLOCK_EQUALS>{WS}	{ /* Skip blank */ }
+<CODEBLOCK_EQUALS>.		{ return yytext[0]; }
+
+<CODEBLOCK>\{			{ yyextra->numOpenBrackets++; appendCodeBlock(yyextra, yytext, 1); }
+<CODEBLOCK>\}			{ 
+	yyextra->numOpenBrackets--; 
+
+	if(yyextra->numOpenBrackets == 0)
+	{
+		BEGIN(CODEBLOCK_END);
+		unput('0');
+	}
+	else
+		appendCodeBlock(yyextra, yytext, 1);
+}
+<CODEBLOCK>.|{SINGLEWS}		{ appendCodeBlock(yyextra, yytext, 1); }
+
+	/* Logic for manually inserting "Index = codeBlockIndex;". We insert arbitrary numbers which allows us to sequentially */
+	/* output all the tokens we need. We use only single-character values so we don't override anything in the text buffer */
+	/* (since the starting value was also a single character "{"). */
+<CODEBLOCK_END>0	{ unput('1'); return TOKEN_INDEX; }
+<CODEBLOCK_END>1	{ unput('2'); return '='; }
+<CODEBLOCK_END>2	{ yylval->intValue = getCodeBlockIndex(yyextra); unput('3'); return TOKEN_INTEGER; }
+<CODEBLOCK_END>3	{ unput('4'); return ';'; }
+<CODEBLOCK_END>4	{ BEGIN(INITIAL); return '}'; }
+<CODEBLOCK_END>.|{WS}	{ /* Never reached */ }
+
+	/* Catch all rules */
+{COMMENT}			{ }
+{IDENTIFIER}		{ yylval->strValue = mmalloc_strdup(yyextra->memContext, yytext); return TOKEN_IDENTIFIER; }
+.					{ return yytext[0]; }
+
 %%
 %%

+ 977 - 977
Source/BansheeSL/BsParserFX.y

@@ -1,978 +1,978 @@
-%{
-#include "BsParserFX.h"
-#include "BsLexerFX.h"
-#define inline
-
-void yyerror(YYLTYPE *locp, ParseState* parse_state, yyscan_t scanner, const char *msg);
-%}
-
-%code requires{
-#include "BsMMAlloc.h"
-#include "BsASTFX.h"
-#include "BsIncludeHandler.h"
-
-#ifndef YY_TYPEDEF_YY_SCANNER_T
-#define YY_TYPEDEF_YY_SCANNER_T
-	typedef void* yyscan_t;
-#endif
-
-typedef struct YYLTYPE {
-	int first_line;
-	int first_column;
-	int last_line;
-	int last_column;
-	char *filename;
-} YYLTYPE;
-#define YYLTYPE_IS_DECLARED 1
-
-#define YYLLOC_DEFAULT(Current, Rhs, N)																\
-	do																								\
-		if (N)																						\
-		{																							\
-			(Current).first_line = YYRHSLOC (Rhs, 1).first_line;									\
-			(Current).first_column = YYRHSLOC (Rhs, 1).first_column;								\
-			(Current).last_line = YYRHSLOC (Rhs, N).last_line;										\
-			(Current).last_column = YYRHSLOC (Rhs, N).last_column;									\
-			(Current).filename = YYRHSLOC (Rhs, 1).filename;										\
-		}																							\
-		else																						\
-		{																							\
-			(Current).first_line = (Current).last_line = YYRHSLOC (Rhs, 0).last_line;				\
-			(Current).first_column = (Current).last_column = YYRHSLOC (Rhs, 0).last_column;			\
-			(Current).filename = NULL;																\
-		}																							\
-	while (0)
-
-#define ADD_PARAMETER(OUTPUT, TYPE, NAME)															\
-			OUTPUT = nodeCreate(parse_state->memContext, NT_Parameter);								\
-			nodePush(parse_state, OUTPUT);															\
-																									\
-			NodeOption paramType;																	\
-			paramType.type = OT_ParamType;															\
-			paramType.value.intValue = TYPE;														\
-																									\
-			NodeOption paramName;																	\
-			paramName.type = OT_Identifier;															\
-			paramName.value.strValue = NAME;														\
-																									\
-			nodeOptionsAdd(parse_state->memContext, parse_state->topNode->options, &paramType);		\
-			nodeOptionsAdd(parse_state->memContext, parse_state->topNode->options, &paramName);		\
-
-}
-
-%output  "BsParserFX.c"
-%defines "BsParserFX.h"
-
-%define api.pure
-%locations
-%lex-param { yyscan_t scanner }
-%parse-param { ParseState* parse_state }
-%parse-param { yyscan_t scanner }
-%glr-parser
-
-%union {
-	int intValue;
-	float floatValue;
-	float matrixValue[16];
-	int intVectorValue[4];
-	const char* strValue;
-	ASTFXNode* nodePtr;
-	NodeOption nodeOption;
-}
-
-	/* Value types */
-%token <intValue>	TOKEN_INTEGER
-%token <floatValue> TOKEN_FLOAT
-%token <intValue>	TOKEN_BOOLEAN
-%token <strValue>	TOKEN_STRING
-%token <strValue>	TOKEN_IDENTIFIER
-
-%token <intValue>	TOKEN_FILLMODEVALUE
-%token <intValue>	TOKEN_CULLMODEVALUE
-%token <intValue>	TOKEN_COMPFUNCVALUE
-%token <intValue>	TOKEN_OPVALUE
-%token <intValue>	TOKEN_COLORMASK
-%token <intValue>	TOKEN_ADDRMODEVALUE
-%token <intValue>	TOKEN_FILTERVALUE
-%token <intValue>	TOKEN_BLENDOPVALUE
-%token <intValue>	TOKEN_BUFFERUSAGE
-
-%token <intValue> TOKEN_FLOATTYPE 
-%token <intValue> TOKEN_FLOAT2TYPE 
-%token <intValue> TOKEN_FLOAT3TYPE 
-%token <intValue> TOKEN_FLOAT4TYPE
-%token <intValue> TOKEN_INTTYPE 
-%token <intValue> TOKEN_INT2TYPE 
-%token <intValue> TOKEN_INT3TYPE 
-%token <intValue> TOKEN_INT4TYPE
-%token <intValue> TOKEN_COLORTYPE
-
-%token <intValue> TOKEN_MAT2x2TYPE 
-%token <intValue> TOKEN_MAT2x3TYPE 
-%token <intValue> TOKEN_MAT2x4TYPE
-
-%token <intValue> TOKEN_MAT3x2TYPE 
-%token <intValue> TOKEN_MAT3x3TYPE 
-%token <intValue> TOKEN_MAT3x4TYPE
-
-%token <intValue> TOKEN_MAT4x2TYPE 
-%token <intValue> TOKEN_MAT4x3TYPE 
-%token <intValue> TOKEN_MAT4x4TYPE
-
-%token <intValue> TOKEN_SAMPLER1D 
-%token <intValue> TOKEN_SAMPLER2D 
-%token <intValue> TOKEN_SAMPLER3D 
-%token <intValue> TOKEN_SAMPLERCUBE 
-%token <intValue> TOKEN_SAMPLER2DMS
-
-%token <intValue> TOKEN_TEXTURE1D 
-%token <intValue> TOKEN_TEXTURE2D 
-%token <intValue> TOKEN_TEXTURE3D 
-%token <intValue> TOKEN_TEXTURECUBE 
-%token <intValue> TOKEN_TEXTURE2DMS
-
-%token <intValue> TOKEN_BYTEBUFFER 
-%token <intValue> TOKEN_STRUCTBUFFER 
-%token <intValue> TOKEN_RWTYPEDBUFFER 
-%token <intValue> TOKEN_RWBYTEBUFFER
-%token <intValue> TOKEN_RWSTRUCTBUFFER 
-%token <intValue> TOKEN_RWAPPENDBUFFER 
-%token <intValue> TOKEN_RWCONSUMEBUFFER
-
-%token TOKEN_PARAMSBLOCK
-
-	/* Qualifiers */
-%token TOKEN_AUTO TOKEN_ALIAS TOKEN_SHARED TOKEN_USAGE
-
-	/* Shader keywords */
-%token TOKEN_SEPARABLE TOKEN_QUEUE TOKEN_PRIORITY TOKEN_TRANSPARENT
-%token TOKEN_PARAMETERS TOKEN_BLOCKS TOKEN_TECHNIQUE
-
-	/* Technique keywords */
-%token	TOKEN_RENDERER TOKEN_LANGUAGE TOKEN_PASS
-
-	/* Pass keywords */
-%token	TOKEN_VERTEX TOKEN_FRAGMENT TOKEN_GEOMETRY TOKEN_HULL TOKEN_DOMAIN TOKEN_COMPUTE TOKEN_COMMON
-%token	TOKEN_STENCILREF
-
-%token	TOKEN_FILLMODE TOKEN_CULLMODE TOKEN_DEPTHBIAS TOKEN_SDEPTHBIAS
-%token	TOKEN_DEPTHCLIP TOKEN_SCISSOR TOKEN_MULTISAMPLE TOKEN_AALINE
-
-%token	TOKEN_DEPTHREAD TOKEN_DEPTHWRITE TOKEN_COMPAREFUNC TOKEN_STENCIL
-%token	TOKEN_STENCILREADMASK TOKEN_STENCILWRITEMASK TOKEN_STENCILOPFRONT TOKEN_STENCILOPBACK
-%token	TOKEN_FAIL TOKEN_ZFAIL
-
-%token	TOKEN_ALPHATOCOVERAGE TOKEN_INDEPENDANTBLEND TOKEN_TARGET TOKEN_INDEX
-%token	TOKEN_BLEND TOKEN_COLOR TOKEN_ALPHA TOKEN_WRITEMASK
-%token	TOKEN_SOURCE TOKEN_DEST TOKEN_OP
-
-	/* Sampler state keywords */
-%token	TOKEN_ADDRMODE TOKEN_MINFILTER TOKEN_MAGFILTER TOKEN_MIPFILTER
-%token	TOKEN_MAXANISO TOKEN_MIPBIAS TOKEN_MIPMIN TOKEN_MIPMAX
-%token	TOKEN_BORDERCOLOR TOKEN_U TOKEN_V TOKEN_W
-
-%type <nodePtr>		shader;
-%type <nodeOption>	shader_statement;
-%type <nodeOption>	shader_option;
-
-%type <nodePtr>		technique;
-%type <nodePtr>		technique_header;
-%type <nodeOption>	technique_statement;
-%type <nodeOption>	technique_option;
-
-%type <nodePtr>		pass;
-%type <nodePtr>		pass_header;
-%type <nodeOption>	pass_statement;
-%type <nodeOption>	pass_option;
-
-%type <nodePtr>		code;
-%type <nodePtr>		code_header;
-
-%type <nodePtr>		stencil_op_front_header;
-%type <nodePtr>		stencil_op_back_header;
-%type <nodeOption>	stencil_op_option;
-
-%type <nodePtr>		target;
-%type <nodePtr>		target_header;
-%type <nodeOption>	target_statement;
-%type <nodeOption>	target_option;
-
-%type <nodePtr>		blend_color_header;
-%type <nodePtr>		blend_alpha_header;
-%type <nodeOption>	blenddef_option;
-
-%type <nodeOption>	sampler_state_option;
-
-%type <nodePtr>		addr_mode;
-%type <nodePtr>		addr_mode_header;
-%type <nodeOption>	addr_mode_option;
-
-%type <nodePtr> parameters
-%type <nodePtr> parameters_header
-%type <nodeOption> parameter
-
-%type <nodePtr> block_header
-%type <nodeOption> block
-%type <nodePtr> blocks_header
-%type <nodePtr> blocks
-
-%type <nodeOption> qualifier
-
-%type <matrixValue> float2;
-%type <matrixValue> float3;
-%type <matrixValue> float4;
-%type <intVectorValue> int2;
-%type <intVectorValue> int3;
-%type <intVectorValue> int4;
-%type <matrixValue> mat6;
-%type <matrixValue> mat8;
-%type <matrixValue> mat9;
-%type <matrixValue> mat12;
-%type <matrixValue> mat16;
-
-%type <nodePtr> param_header_float
-%type <nodePtr> param_header_float2
-%type <nodePtr> param_header_float3
-%type <nodePtr> param_header_float4
-%type <nodePtr> param_header_int
-%type <nodePtr> param_header_int2
-%type <nodePtr> param_header_int3
-%type <nodePtr> param_header_int4
-%type <nodePtr> param_header_color
-%type <nodePtr> param_header_mat2x2
-%type <nodePtr> param_header_mat2x3
-%type <nodePtr> param_header_mat2x4
-%type <nodePtr> param_header_mat3x2
-%type <nodePtr> param_header_mat3x3
-%type <nodePtr> param_header_mat3x4
-%type <nodePtr> param_header_mat4x2
-%type <nodePtr> param_header_mat4x3
-%type <nodePtr> param_header_mat4x4
-%type <nodePtr> param_header_sampler
-%type <nodePtr> param_header_texture
-%type <nodePtr> param_header_buffer
-%type <nodePtr> param_header_qualified_sampler
-
-%type <nodeOption> param_body_float
-%type <nodeOption> param_body_float2
-%type <nodeOption> param_body_float3
-%type <nodeOption> param_body_float4
-%type <nodeOption> param_body_int
-%type <nodeOption> param_body_int2
-%type <nodeOption> param_body_int3
-%type <nodeOption> param_body_int4
-%type <nodeOption> param_body_mat6
-%type <nodeOption> param_body_mat8
-%type <nodeOption> param_body_mat9
-%type <nodeOption> param_body_mat12
-%type <nodeOption> param_body_mat16
-%type <nodeOption> param_body_sampler
-%type <nodeOption> param_body_tex
-
-%%
-
-	/* Shader */
-
-shader
-	: /* empty */				{ }
-	| shader_statement shader	{ nodeOptionsAdd(parse_state->memContext, parse_state->topNode->options, &$1); }
-	;
-
-shader_statement
-	: shader_option
-	| technique			{ $$.type = OT_Technique; $$.value.nodePtr = $1; }
-	| parameters		{ $$.type = OT_Parameters; $$.value.nodePtr = $1; }
-	| blocks			{ $$.type = OT_Blocks; $$.value.nodePtr = $1; }
-	;
-
-shader_option
-	: TOKEN_SEPARABLE '=' TOKEN_BOOLEAN ';'		{ $$.type = OT_Separable; $$.value.intValue = $3; }
-	| TOKEN_QUEUE '=' TOKEN_INTEGER ';'			{ $$.type = OT_Queue; $$.value.intValue = $3; }
-	| TOKEN_PRIORITY '=' TOKEN_INTEGER ';'		{ $$.type = OT_Priority; $$.value.intValue = $3; }
-	| TOKEN_TRANSPARENT '=' TOKEN_BOOLEAN ';'	{ $$.type = OT_Transparent; $$.value.intValue = $3; }
-	;
-
-	/* Technique */
-
-technique
-	: technique_header '{' technique_body '}' ';' { nodePop(parse_state); $$ = $1; }
-	;
-
-technique_header
-	: TOKEN_TECHNIQUE '=' 
-		{ 
-			$$ = nodeCreate(parse_state->memContext, NT_Technique); 
-			nodePush(parse_state, $$);
-		}
-	;
-
-technique_body
-	: /* empty */
-	| technique_statement technique_body		{ nodeOptionsAdd(parse_state->memContext, parse_state->topNode->options, &$1); }
-	;
-
-technique_statement
-	: technique_option
-	| pass				{ $$.type = OT_Pass; $$.value.nodePtr = $1; }
-	| pass_option
-	| code				{ $$.type = OT_Code; $$.value.nodePtr = $1; }
-	;
-
-technique_option
-	: TOKEN_RENDERER '=' TOKEN_STRING ';'	{ $$.type = OT_Renderer; $$.value.strValue = $3; }
-	| TOKEN_LANGUAGE '=' TOKEN_STRING ';'	{ $$.type = OT_Language; $$.value.strValue = $3; }
-	;
-
-	/* Pass */
-
-pass
-	: pass_header '{' pass_body '}' ';' { nodePop(parse_state); $$ = $1; }
-	;
-
-pass_header
-	: TOKEN_PASS '=' 
-		{ 
-			$$ = nodeCreate(parse_state->memContext, NT_Pass); 
-			nodePush(parse_state, $$);
-		}
-	;
-
-pass_body
-	: /* empty */
-	| pass_statement pass_body		{ nodeOptionsAdd(parse_state->memContext, parse_state->topNode->options, &$1); }
-	;
-
-pass_statement
-	: pass_option
-	| code				{ $$.type = OT_Code; $$.value.nodePtr = $1; }
-	;
-
-pass_option
-	: TOKEN_INDEX '=' TOKEN_INTEGER ';'							{ $$.type = OT_Index; $$.value.intValue = $3; }
-	| TOKEN_FILLMODE '=' TOKEN_FILLMODEVALUE ';'				{ $$.type = OT_FillMode; $$.value.intValue = $3; }
-	| TOKEN_CULLMODE '=' TOKEN_CULLMODEVALUE ';'				{ $$.type = OT_CullMode; $$.value.intValue = $3; }
-	| TOKEN_DEPTHBIAS '=' TOKEN_FLOAT ';'						{ $$.type = OT_DepthBias; $$.value.floatValue = $3; }
-	| TOKEN_SDEPTHBIAS '=' TOKEN_FLOAT ';'						{ $$.type = OT_SDepthBias; $$.value.floatValue = $3; }
-	| TOKEN_DEPTHCLIP '=' TOKEN_BOOLEAN ';'						{ $$.type = OT_DepthClip; $$.value.intValue = $3; }
-	| TOKEN_SCISSOR '=' TOKEN_BOOLEAN ';'						{ $$.type = OT_Scissor; $$.value.intValue = $3; }
-	| TOKEN_MULTISAMPLE '=' TOKEN_BOOLEAN ';'					{ $$.type = OT_Multisample; $$.value.intValue = $3; }
-	| TOKEN_AALINE '=' TOKEN_BOOLEAN ';'						{ $$.type = OT_AALine; $$.value.intValue = $3; }
-	| TOKEN_DEPTHREAD '=' TOKEN_BOOLEAN ';'						{ $$.type = OT_DepthRead; $$.value.intValue = $3; }
-	| TOKEN_DEPTHWRITE '=' TOKEN_BOOLEAN ';'					{ $$.type = OT_DepthWrite; $$.value.intValue = $3; }
-	| TOKEN_COMPAREFUNC '=' TOKEN_COMPFUNCVALUE ';'				{ $$.type = OT_CompareFunc; $$.value.intValue = $3; }
-	| TOKEN_STENCIL '=' TOKEN_BOOLEAN ';'						{ $$.type = OT_Stencil; $$.value.intValue = $3; }
-	| TOKEN_STENCILREADMASK '=' TOKEN_INTEGER ';'				{ $$.type = OT_StencilReadMask; $$.value.intValue = $3; }
-	| TOKEN_STENCILWRITEMASK '=' TOKEN_INTEGER ';'				{ $$.type = OT_StencilWriteMask; $$.value.intValue = $3; }
-	| stencil_op_front_header '{' stencil_op_body '}' ';'		{ nodePop(parse_state); $$.type = OT_StencilOpFront; $$.value.nodePtr = $1; }
-	| stencil_op_back_header '{' stencil_op_body '}' ';'		{ nodePop(parse_state); $$.type = OT_StencilOpBack; $$.value.nodePtr = $1; }
-	| stencil_op_front_header '{' stencil_op_body_init '}' ';'	{ nodePop(parse_state); $$.type = OT_StencilOpFront; $$.value.nodePtr = $1; }
-	| stencil_op_back_header '{' stencil_op_body_init '}' ';'	{ nodePop(parse_state); $$.type = OT_StencilOpBack; $$.value.nodePtr = $1; }
-	| TOKEN_ALPHATOCOVERAGE '=' TOKEN_BOOLEAN ';'				{ $$.type = OT_AlphaToCoverage; $$.value.intValue = $3; }
-	| TOKEN_INDEPENDANTBLEND '=' TOKEN_BOOLEAN ';'				{ $$.type = OT_IndependantBlend; $$.value.intValue = $3; }
-	| target													{ $$.type = OT_Target; $$.value.nodePtr = $1; }
-	| TOKEN_STENCILREF '=' TOKEN_INTEGER ';'					{ $$.type = OT_StencilRef; $$.value.intValue = $3; }
-	;
-
-	/* Code blocks */
-
-code
-	: code_header '{' TOKEN_INDEX '=' TOKEN_INTEGER ';' '}' ';'
-	{
-		NodeOption index;
-		index.type = OT_Index; 
-		index.value.intValue = $5;
-
-		nodeOptionsAdd(parse_state->memContext, parse_state->topNode->options, &index);
-
-		nodePop(parse_state); 
-		$$ = $1;
-	}
-	;
-
-code_header
-	: TOKEN_VERTEX '='
-		{ 
-			$$ = nodeCreate(parse_state->memContext, NT_CodeVertex); 
-			nodePush(parse_state, $$);
-		}
-	| TOKEN_FRAGMENT '='
-		{ 
-			$$ = nodeCreate(parse_state->memContext, NT_CodeFragment); 
-			nodePush(parse_state, $$);
-		}
-	| TOKEN_GEOMETRY '='
-		{ 
-			$$ = nodeCreate(parse_state->memContext, NT_CodeGeometry); 
-			nodePush(parse_state, $$);
-		}
-	| TOKEN_HULL '='
-		{ 
-			$$ = nodeCreate(parse_state->memContext, NT_CodeHull); 
-			nodePush(parse_state, $$);
-		}
-	| TOKEN_DOMAIN '='
-		{ 
-			$$ = nodeCreate(parse_state->memContext, NT_CodeDomain); 
-			nodePush(parse_state, $$);
-		}
-	| TOKEN_COMPUTE '='
-		{ 
-			$$ = nodeCreate(parse_state->memContext, NT_CodeCompute); 
-			nodePush(parse_state, $$);
-		}
-	| TOKEN_COMMON '='
-		{ 
-			$$ = nodeCreate(parse_state->memContext, NT_CodeCommon); 
-			nodePush(parse_state, $$);
-		}
-	;
-
-	/* Stencil op */
-
-stencil_op_front_header
-	: TOKEN_STENCILOPFRONT '='
-		{ 
-			$$ = nodeCreate(parse_state->memContext, NT_StencilOp); 
-			nodePush(parse_state, $$);
-		}
-	;
-
-stencil_op_back_header
-	: TOKEN_STENCILOPBACK '='
-		{ 
-			$$ = nodeCreate(parse_state->memContext, NT_StencilOp); 
-			nodePush(parse_state, $$);
-		}
-	;
-
-stencil_op_body_init
-	: TOKEN_OPVALUE ',' TOKEN_OPVALUE ',' TOKEN_OPVALUE ',' TOKEN_COMPFUNCVALUE
-		{
-			NodeOption fail; fail.type = OT_Fail; fail.value.intValue = $1;
-			NodeOption zfail; zfail.type = OT_ZFail; zfail.value.intValue = $3;
-			NodeOption pass; pass.type = OT_PassOp; pass.value.intValue = $5;
-			NodeOption cmp; cmp.type = OT_CompareFunc; cmp.value.intValue = $7;
-
-			nodeOptionsAdd(parse_state->memContext, parse_state->topNode->options, &fail);
-			nodeOptionsAdd(parse_state->memContext, parse_state->topNode->options, &zfail);
-			nodeOptionsAdd(parse_state->memContext, parse_state->topNode->options, &pass);
-			nodeOptionsAdd(parse_state->memContext, parse_state->topNode->options, &cmp);
-		}
-	;
-
-stencil_op_body
-	: /* empty */
-	| stencil_op_option stencil_op_body		{ nodeOptionsAdd(parse_state->memContext, parse_state->topNode->options, &$1); }
-	;
-
-stencil_op_option
-	: TOKEN_FAIL '=' TOKEN_OPVALUE ';'					{ $$.type = OT_Fail; $$.value.intValue = $3; }
-	| TOKEN_ZFAIL '=' TOKEN_OPVALUE ';'					{ $$.type = OT_ZFail; $$.value.intValue = $3; }
-	| TOKEN_PASS '=' TOKEN_OPVALUE ';'					{ $$.type = OT_PassOp; $$.value.intValue = $3; }
-	| TOKEN_COMPAREFUNC '=' TOKEN_COMPFUNCVALUE ';'		{ $$.type = OT_CompareFunc; $$.value.intValue = $3; }
-	; 
-
-	/* Target */
-target
-	: target_header '{' target_body '}' ';' { nodePop(parse_state); $$ = $1; }
-	;
-
-target_header
-	: TOKEN_TARGET '='
-		{ 
-			$$ = nodeCreate(parse_state->memContext, NT_Target); 
-			nodePush(parse_state, $$);
-		}
-	;
-
-target_body
-	: /* empty */
-	| target_statement target_body		{ nodeOptionsAdd(parse_state->memContext, parse_state->topNode->options, &$1); }
-	;
-
-target_statement
-	: target_option
-	;
-
-target_option
-	: TOKEN_INDEX '=' TOKEN_INTEGER ';'					{ $$.type = OT_Index; $$.value.intValue = $3; }
-	| TOKEN_BLEND '=' TOKEN_BOOLEAN ';'					{ $$.type = OT_Blend; $$.value.intValue = $3; }
-	| blend_color_header '{' blenddef_body '}' ';'		{ nodePop(parse_state); $$.type = OT_Color; $$.value.nodePtr = $1; }
-	| blend_alpha_header '{' blenddef_body '}' ';'		{ nodePop(parse_state); $$.type = OT_Alpha; $$.value.nodePtr = $1; }
-	| blend_color_header '{' blenddef_body_init '}' ';'		{ nodePop(parse_state); $$.type = OT_Color; $$.value.nodePtr = $1; }
-	| blend_alpha_header '{' blenddef_body_init '}' ';'		{ nodePop(parse_state); $$.type = OT_Alpha; $$.value.nodePtr = $1; }
-	| TOKEN_WRITEMASK '=' TOKEN_COLORMASK ';'			{ $$.type = OT_WriteMask; $$.value.intValue = $3; }
-	;
-
-	/* Blend definition */
-blend_color_header
-	: TOKEN_COLOR '='
-		{ 
-			$$ = nodeCreate(parse_state->memContext, NT_BlendDef); 
-			nodePush(parse_state, $$);
-		}
-	;
-
-blend_alpha_header
-	: TOKEN_ALPHA '='
-		{ 
-			$$ = nodeCreate(parse_state->memContext, NT_BlendDef); 
-			nodePush(parse_state, $$);
-		}
-	;
-
-blenddef_body
-	: /* empty */
-	| blenddef_option blenddef_body		{ nodeOptionsAdd(parse_state->memContext, parse_state->topNode->options, &$1); }
-	;
-
-blenddef_body_init
-	: TOKEN_OPVALUE ',' TOKEN_OPVALUE ',' TOKEN_BLENDOPVALUE
-		{
-			NodeOption src; src.type = OT_Source; src.value.intValue = $1;
-			NodeOption dst; dst.type = OT_Dest; dst.value.intValue = $3;
-			NodeOption op; op.type = OT_Op; op.value.intValue = $5;
-
-			nodeOptionsAdd(parse_state->memContext, parse_state->topNode->options, &src);
-			nodeOptionsAdd(parse_state->memContext, parse_state->topNode->options, &dst);
-			nodeOptionsAdd(parse_state->memContext, parse_state->topNode->options, &op);
-		}
-	;
-
-blenddef_option
-	: TOKEN_SOURCE '=' TOKEN_OPVALUE ';'					{ $$.type = OT_Source; $$.value.intValue = $3; }
-	| TOKEN_DEST '=' TOKEN_OPVALUE ';'						{ $$.type = OT_Dest; $$.value.intValue = $3; }
-	| TOKEN_OP '=' TOKEN_BLENDOPVALUE ';'					{ $$.type = OT_Op; $$.value.intValue = $3; }
-	;
-
-	/* Sampler state */
-
-sampler_state_body
-	: /* empty */
-	| sampler_state_option sampler_state_body		{ nodeOptionsAdd(parse_state->memContext, parse_state->topNode->options, &$1); }
-	;
-
-sampler_state_option
-	: addr_mode												{ $$.type = OT_AddrMode; $$.value.nodePtr = $1; }
-	| TOKEN_MINFILTER '=' TOKEN_FILTERVALUE ';'				{ $$.type = OT_MinFilter; $$.value.intValue = $3; }
-	| TOKEN_MAGFILTER '=' TOKEN_FILTERVALUE ';'				{ $$.type = OT_MagFilter; $$.value.intValue = $3; }
-	| TOKEN_MIPFILTER '=' TOKEN_FILTERVALUE ';'				{ $$.type = OT_MipFilter; $$.value.intValue = $3; }
-	| TOKEN_MAXANISO '=' TOKEN_INTEGER ';'					{ $$.type = OT_MaxAniso; $$.value.intValue = $3; }
-	| TOKEN_MIPBIAS '=' TOKEN_FLOAT ';'						{ $$.type = OT_MipBias; $$.value.floatValue = $3; }
-	| TOKEN_MIPMIN '=' TOKEN_FLOAT ';'						{ $$.type = OT_MipMin; $$.value.floatValue = $3; }
-	| TOKEN_MIPMAX '=' TOKEN_FLOAT ';'						{ $$.type = OT_MipMax; $$.value.floatValue = $3; }
-	| TOKEN_BORDERCOLOR '=' float4 ';'						{ $$.type = OT_BorderColor; memcpy($$.value.matrixValue, $3, sizeof($3)); }
-	| TOKEN_COMPAREFUNC '=' TOKEN_COMPFUNCVALUE ';'			{ $$.type = OT_CompareFunc; $$.value.intValue = $3; }
-	;
-
-	/* Addresing mode */
-addr_mode
-	: addr_mode_header '{' addr_mode_body '}' ';'		{ nodePop(parse_state); $$ = $1; }
-	| addr_mode_header '{' addr_mode_body_init '}' ';'	{ nodePop(parse_state); $$ = $1; }
-	;
-
-addr_mode_header
-	: TOKEN_ADDRMODE '='
-		{ 
-			$$ = nodeCreate(parse_state->memContext, NT_AddrMode); 
-			nodePush(parse_state, $$);
-		}
-	;
-
-addr_mode_body_init
-	: TOKEN_ADDRMODEVALUE ',' TOKEN_ADDRMODEVALUE ',' TOKEN_ADDRMODEVALUE
-		{
-			NodeOption u; u.type = OT_U; u.value.intValue = $1;
-			NodeOption v; v.type = OT_V; v.value.intValue = $3;
-			NodeOption w; w.type = OT_W; w.value.intValue = $5;
-
-			nodeOptionsAdd(parse_state->memContext, parse_state->topNode->options, &u);
-			nodeOptionsAdd(parse_state->memContext, parse_state->topNode->options, &v);
-			nodeOptionsAdd(parse_state->memContext, parse_state->topNode->options, &w);
-		}
-	;
-
-addr_mode_body
-	: /* empty */
-	| addr_mode_option addr_mode_body		{ nodeOptionsAdd(parse_state->memContext, parse_state->topNode->options, &$1); }
-	;
-
-addr_mode_option
-	: TOKEN_U '=' TOKEN_ADDRMODEVALUE ';'					{ $$.type = OT_U; $$.value.intValue = $3; }
-	| TOKEN_V '=' TOKEN_ADDRMODEVALUE ';'					{ $$.type = OT_V; $$.value.intValue = $3; }
-	| TOKEN_W '=' TOKEN_ADDRMODEVALUE ';'					{ $$.type = OT_W; $$.value.intValue = $3; }
-	;
-
-	/* Value types */
-float2
-	: '{' TOKEN_FLOAT ',' TOKEN_FLOAT '}'	{ $$[0] = $2; $$[1] = $4; }
-	;
-
-float3
-	: '{' TOKEN_FLOAT ',' TOKEN_FLOAT ',' TOKEN_FLOAT '}'	{ $$[0] = $2; $$[1] = $4; $$[2] = $6; }
-	;
-
-float4
-	: '{' TOKEN_FLOAT ',' TOKEN_FLOAT ',' TOKEN_FLOAT ',' TOKEN_FLOAT '}'	{ $$[0] = $2; $$[1] = $4; $$[2] = $6; $$[3] = $8;}
-	;
-
-int2
-	: '{' TOKEN_INTEGER ',' TOKEN_INTEGER '}'	{ $$[0] = $2; $$[1] = $4; }
-	;
-
-int3
-	: '{' TOKEN_INTEGER ',' TOKEN_INTEGER ',' TOKEN_INTEGER '}'	{ $$[0] = $2; $$[1] = $4; $$[2] = $6; }
-	;
-
-int4
-	: '{' TOKEN_INTEGER ',' TOKEN_INTEGER ',' TOKEN_INTEGER ',' TOKEN_INTEGER '}'	{ $$[0] = $2; $$[1] = $4; $$[2] = $6; $$[3] = $8;}
-	;
-
-mat6
-	: '{' TOKEN_FLOAT ',' TOKEN_FLOAT ',' TOKEN_FLOAT ',' 
-		  TOKEN_FLOAT ',' TOKEN_FLOAT ',' TOKEN_FLOAT '}'	
-		{ 
-			$$[0] = $2; $$[1] = $4; $$[2] = $6; 
-			$$[3] = $8; $$[4] = $10; $$[5] = $12;
-		}
-	;
-
-mat8
-	: '{' TOKEN_FLOAT ',' TOKEN_FLOAT ',' TOKEN_FLOAT ',' 
-		  TOKEN_FLOAT ',' TOKEN_FLOAT ',' TOKEN_FLOAT ',' 
-		  TOKEN_FLOAT ',' TOKEN_FLOAT '}'	
-		{ 
-			$$[0] = $2; $$[1] = $4; $$[2] = $6; 
-			$$[3] = $8; $$[4] = $10; $$[5] = $12;
-			$$[6] = $14; $$[7] = $16;
-		}
-	;
-
-mat9
-	: '{' TOKEN_FLOAT ',' TOKEN_FLOAT ',' TOKEN_FLOAT ',' 
-		  TOKEN_FLOAT ',' TOKEN_FLOAT ',' TOKEN_FLOAT ',' 
-		  TOKEN_FLOAT ',' TOKEN_FLOAT ',' TOKEN_FLOAT '}'	
-		{ 
-			$$[0] = $2; $$[1] = $4; $$[2] = $6; 
-			$$[3] = $8; $$[4] = $10; $$[5] = $12;
-			$$[6] = $14; $$[7] = $16; $$[8] = $18;
-		}
-	;
-
-mat12
-	: '{' TOKEN_FLOAT ',' TOKEN_FLOAT ',' TOKEN_FLOAT ',' TOKEN_FLOAT ',' 
-		  TOKEN_FLOAT ',' TOKEN_FLOAT ',' TOKEN_FLOAT ',' TOKEN_FLOAT ',' 
-		  TOKEN_FLOAT ',' TOKEN_FLOAT ',' TOKEN_FLOAT ',' TOKEN_FLOAT '}'	
-		{ 
-			$$[0] = $2; $$[1] = $4; $$[2] = $6; $$[3] = $8; 
-			$$[4] = $10; $$[5] = $12; $$[6] = $14; $$[7] = $16; 
-			$$[8] = $18; $$[9] = $20; $$[10] = $22; $$[11] = $24;
-		}
-	;
-
-mat16
-	: '{' TOKEN_FLOAT ',' TOKEN_FLOAT ',' TOKEN_FLOAT ',' TOKEN_FLOAT ',' 
-		  TOKEN_FLOAT ',' TOKEN_FLOAT ',' TOKEN_FLOAT ',' TOKEN_FLOAT ',' 
-		  TOKEN_FLOAT ',' TOKEN_FLOAT ',' TOKEN_FLOAT ',' TOKEN_FLOAT ',' 
-		  TOKEN_FLOAT ',' TOKEN_FLOAT ',' TOKEN_FLOAT ',' TOKEN_FLOAT '}'	
-		{ 
-			$$[0] = $2; $$[1] = $4; $$[2] = $6; $$[3] = $8; 
-			$$[4] = $10; $$[5] = $12; $$[6] = $14; $$[7] = $16; 
-			$$[8] = $18; $$[9] = $20; $$[10] = $22; $$[11] = $24;
-			$$[12] = $26; $$[13] = $28; $$[14] = $30; $$[15] = $32;
-		}
-	;
-
-	/* Parameters */
-parameters
-	: parameters_header '{' parameters_body '}' ';' { nodePop(parse_state); $$ = $1; }
-	;
-
-parameters_header
-	: TOKEN_PARAMETERS '='
-		{ 
-			$$ = nodeCreate(parse_state->memContext, NT_Parameters); 
-			nodePush(parse_state, $$);
-		}
-	;
-
-parameters_body
-	: /* empty */
-	| parameter parameters_body		{ nodeOptionsAdd(parse_state->memContext, parse_state->topNode->options, &$1); }
-	;
-
-parameter
-	: param_header_float	qualifier_list param_body_float		';' { nodeOptionsAdd(parse_state->memContext, parse_state->topNode->options, &$3); nodePop(parse_state); $$.type = OT_Parameter; $$.value.nodePtr = $1; }
-	| param_header_float2	qualifier_list param_body_float2	';' { nodeOptionsAdd(parse_state->memContext, parse_state->topNode->options, &$3); nodePop(parse_state); $$.type = OT_Parameter; $$.value.nodePtr = $1; }
-	| param_header_float3	qualifier_list param_body_float3	';' { nodeOptionsAdd(parse_state->memContext, parse_state->topNode->options, &$3); nodePop(parse_state); $$.type = OT_Parameter; $$.value.nodePtr = $1; }
-	| param_header_float4	qualifier_list param_body_float4	';' { nodeOptionsAdd(parse_state->memContext, parse_state->topNode->options, &$3); nodePop(parse_state); $$.type = OT_Parameter; $$.value.nodePtr = $1; }
-	| param_header_int		qualifier_list param_body_int		';' { nodeOptionsAdd(parse_state->memContext, parse_state->topNode->options, &$3); nodePop(parse_state); $$.type = OT_Parameter; $$.value.nodePtr = $1; }
-	| param_header_int2		qualifier_list param_body_int2		';' { nodeOptionsAdd(parse_state->memContext, parse_state->topNode->options, &$3); nodePop(parse_state); $$.type = OT_Parameter; $$.value.nodePtr = $1; }
-	| param_header_int3		qualifier_list param_body_int3		';' { nodeOptionsAdd(parse_state->memContext, parse_state->topNode->options, &$3); nodePop(parse_state); $$.type = OT_Parameter; $$.value.nodePtr = $1; }
-	| param_header_int4		qualifier_list param_body_int4		';' { nodeOptionsAdd(parse_state->memContext, parse_state->topNode->options, &$3); nodePop(parse_state); $$.type = OT_Parameter; $$.value.nodePtr = $1; }
-	| param_header_color	qualifier_list param_body_float4	';' { nodeOptionsAdd(parse_state->memContext, parse_state->topNode->options, &$3); nodePop(parse_state); $$.type = OT_Parameter; $$.value.nodePtr = $1; }
-	| param_header_mat2x2	qualifier_list param_body_float4	';' { nodeOptionsAdd(parse_state->memContext, parse_state->topNode->options, &$3); nodePop(parse_state); $$.type = OT_Parameter; $$.value.nodePtr = $1; }
-	| param_header_mat2x3	qualifier_list param_body_mat6		';' { nodeOptionsAdd(parse_state->memContext, parse_state->topNode->options, &$3); nodePop(parse_state); $$.type = OT_Parameter; $$.value.nodePtr = $1; }
-	| param_header_mat2x4	qualifier_list param_body_mat8		';' { nodeOptionsAdd(parse_state->memContext, parse_state->topNode->options, &$3); nodePop(parse_state); $$.type = OT_Parameter; $$.value.nodePtr = $1; }
-	| param_header_mat3x2	qualifier_list param_body_mat6		';' { nodeOptionsAdd(parse_state->memContext, parse_state->topNode->options, &$3); nodePop(parse_state); $$.type = OT_Parameter; $$.value.nodePtr = $1; }
-	| param_header_mat3x3	qualifier_list param_body_mat9		';' { nodeOptionsAdd(parse_state->memContext, parse_state->topNode->options, &$3); nodePop(parse_state); $$.type = OT_Parameter; $$.value.nodePtr = $1; }
-	| param_header_mat3x4	qualifier_list param_body_mat12		';' { nodeOptionsAdd(parse_state->memContext, parse_state->topNode->options, &$3); nodePop(parse_state); $$.type = OT_Parameter; $$.value.nodePtr = $1; }
-	| param_header_mat4x2	qualifier_list param_body_mat8		';' { nodeOptionsAdd(parse_state->memContext, parse_state->topNode->options, &$3); nodePop(parse_state); $$.type = OT_Parameter; $$.value.nodePtr = $1; }
-	| param_header_mat4x3	qualifier_list param_body_mat12		';' { nodeOptionsAdd(parse_state->memContext, parse_state->topNode->options, &$3); nodePop(parse_state); $$.type = OT_Parameter; $$.value.nodePtr = $1; }
-	| param_header_mat4x4	qualifier_list param_body_mat16		';' { nodeOptionsAdd(parse_state->memContext, parse_state->topNode->options, &$3); nodePop(parse_state); $$.type = OT_Parameter; $$.value.nodePtr = $1; }
-	| param_header_texture	qualifier_list param_body_tex		';' { nodeOptionsAdd(parse_state->memContext, parse_state->topNode->options, &$3); nodePop(parse_state); $$.type = OT_Parameter; $$.value.nodePtr = $1; }
-	| param_header_buffer	qualifier_list						';' { nodePop(parse_state); $$.type = OT_Parameter; $$.value.nodePtr = $1; }
-	| param_header_qualified_sampler		param_body_sampler	';' 
-		{ 
-			nodePop(parse_state);
-
-			NodeOption samplerState;
-			samplerState.type = OT_SamplerState;
-			samplerState.value.nodePtr = $1;
-
-			nodeOptionsAdd(parse_state->memContext, parse_state->topNode->options, &samplerState); 
-
-			$$.type = OT_Parameter; $$.value.nodePtr = parse_state->topNode; 
-			nodePop(parse_state); 
-		}
-	;
-
-param_header_float 
-	: TOKEN_FLOATTYPE TOKEN_IDENTIFIER { ADD_PARAMETER($$, $1, $2); }
-	;
-
-param_header_float2
-	: TOKEN_FLOAT2TYPE TOKEN_IDENTIFIER { ADD_PARAMETER($$, $1, $2); }
-	;
-
-param_header_float3
-	: TOKEN_FLOAT3TYPE TOKEN_IDENTIFIER { ADD_PARAMETER($$, $1, $2); }
-	;
-
-param_header_float4 
-	: TOKEN_FLOAT4TYPE TOKEN_IDENTIFIER { ADD_PARAMETER($$, $1, $2); }
-	;
-
-param_header_int 
-	: TOKEN_INTTYPE TOKEN_IDENTIFIER { ADD_PARAMETER($$, $1, $2); }
-	;
-
-param_header_int2
-	: TOKEN_INT2TYPE TOKEN_IDENTIFIER { ADD_PARAMETER($$, $1, $2); }
-	;
-
-param_header_int3
-	: TOKEN_INT3TYPE TOKEN_IDENTIFIER { ADD_PARAMETER($$, $1, $2); }
-	;
-
-param_header_int4
-	: TOKEN_INT4TYPE TOKEN_IDENTIFIER { ADD_PARAMETER($$, $1, $2); }
-	;
-
-param_header_color
-	: TOKEN_COLORTYPE TOKEN_IDENTIFIER { ADD_PARAMETER($$, $1, $2); }
-	;
-
-param_header_mat2x2
-	: TOKEN_MAT2x2TYPE TOKEN_IDENTIFIER { ADD_PARAMETER($$, $1, $2); }
-	;
-
-param_header_mat2x3
-	: TOKEN_MAT2x3TYPE TOKEN_IDENTIFIER { ADD_PARAMETER($$, $1, $2); }
-	;
-
-param_header_mat2x4
-	: TOKEN_MAT2x4TYPE TOKEN_IDENTIFIER { ADD_PARAMETER($$, $1, $2); }
-	;
-
-param_header_mat3x2
-	: TOKEN_MAT3x2TYPE TOKEN_IDENTIFIER { ADD_PARAMETER($$, $1, $2); }
-	;
-
-param_header_mat3x3
-	: TOKEN_MAT3x3TYPE TOKEN_IDENTIFIER { ADD_PARAMETER($$, $1, $2); }
-	;
-
-param_header_mat3x4
-	: TOKEN_MAT3x4TYPE TOKEN_IDENTIFIER { ADD_PARAMETER($$, $1, $2); }
-	;
-
-param_header_mat4x2
-	: TOKEN_MAT4x2TYPE TOKEN_IDENTIFIER { ADD_PARAMETER($$, $1, $2); }
-	;
-
-param_header_mat4x3
-	: TOKEN_MAT4x3TYPE TOKEN_IDENTIFIER { ADD_PARAMETER($$, $1, $2); }
-	;
-
-param_header_mat4x4
-	: TOKEN_MAT4x4TYPE TOKEN_IDENTIFIER { ADD_PARAMETER($$, $1, $2); }
-	;
-
-param_header_sampler
-	: TOKEN_SAMPLER1D TOKEN_IDENTIFIER { ADD_PARAMETER($$, $1, $2); }
-	| TOKEN_SAMPLER2D TOKEN_IDENTIFIER { ADD_PARAMETER($$, $1, $2); }
-	| TOKEN_SAMPLER3D TOKEN_IDENTIFIER { ADD_PARAMETER($$, $1, $2); }
-	| TOKEN_SAMPLERCUBE TOKEN_IDENTIFIER { ADD_PARAMETER($$, $1, $2); }
-	| TOKEN_SAMPLER2DMS TOKEN_IDENTIFIER { ADD_PARAMETER($$, $1, $2); }
-	;
-
-param_header_texture
-	: TOKEN_TEXTURE1D		TOKEN_IDENTIFIER { ADD_PARAMETER($$, $1, $2); }
-	| TOKEN_TEXTURE2D		TOKEN_IDENTIFIER { ADD_PARAMETER($$, $1, $2); }
-	| TOKEN_TEXTURE3D		TOKEN_IDENTIFIER { ADD_PARAMETER($$, $1, $2); }
-	| TOKEN_TEXTURECUBE		TOKEN_IDENTIFIER { ADD_PARAMETER($$, $1, $2); }
-	| TOKEN_TEXTURE2DMS		TOKEN_IDENTIFIER { ADD_PARAMETER($$, $1, $2); }
-	;
-
-param_header_buffer
-	: TOKEN_BYTEBUFFER		TOKEN_IDENTIFIER { ADD_PARAMETER($$, $1, $2); }
-	| TOKEN_STRUCTBUFFER	TOKEN_IDENTIFIER { ADD_PARAMETER($$, $1, $2); }
-	| TOKEN_RWTYPEDBUFFER	TOKEN_IDENTIFIER { ADD_PARAMETER($$, $1, $2); }
-	| TOKEN_RWBYTEBUFFER	TOKEN_IDENTIFIER { ADD_PARAMETER($$, $1, $2); }
-	| TOKEN_RWSTRUCTBUFFER	TOKEN_IDENTIFIER { ADD_PARAMETER($$, $1, $2); }
-	| TOKEN_RWAPPENDBUFFER	TOKEN_IDENTIFIER { ADD_PARAMETER($$, $1, $2); }
-	| TOKEN_RWCONSUMEBUFFER TOKEN_IDENTIFIER { ADD_PARAMETER($$, $1, $2); }
-	;
-
-param_header_qualified_sampler
-	: param_header_sampler qualifier_list	
-		{ 
-			$$ = nodeCreate(parse_state->memContext, NT_SamplerState); 
-			nodePush(parse_state, $$);
-		}
-	;
-
-param_body_float 
-	: /* empty */		{ $$.type = OT_None; }
-	| '=' TOKEN_FLOAT	{ $$.type = OT_ParamValue; $$.value.floatValue = $2; }
-	;
-
-param_body_float2
-	: /* empty */		{ $$.type = OT_None; }
-	| '=' float2		{ $$.type = OT_ParamValue; memcpy($$.value.matrixValue, $2, sizeof($2)); }
-	;
-
-param_body_float3
-	: /* empty */		{ $$.type = OT_None; }
-	| '=' float3		{ $$.type = OT_ParamValue; memcpy($$.value.matrixValue, $2, sizeof($2)); }
-	;
-
-param_body_float4
-	: /* empty */		{ $$.type = OT_None; }
-	| '=' float4		{ $$.type = OT_ParamValue; memcpy($$.value.matrixValue, $2, sizeof($2)); }
-	;
-
-param_body_int
-	: /* empty */		{ $$.type = OT_None; }
-	| '=' TOKEN_INTEGER	{ $$.type = OT_ParamValue; $$.value.intValue = $2; }
-	;
-
-param_body_int2
-	: /* empty */		{ $$.type = OT_None; }
-	| '=' int2			{ $$.type = OT_ParamValue; memcpy($$.value.intVectorValue, $2, sizeof($2)); }
-	;
-
-param_body_int3
-	: /* empty */		{ $$.type = OT_None; }
-	| '=' int3			{ $$.type = OT_ParamValue; memcpy($$.value.intVectorValue, $2, sizeof($2)); }
-	;
-
-param_body_int4
-	: /* empty */		{ $$.type = OT_None; }
-	| '=' int4			{ $$.type = OT_ParamValue; memcpy($$.value.intVectorValue, $2, sizeof($2)); }
-	;
-
-param_body_mat6
-	: /* empty */		{ $$.type = OT_None; }
-	| '=' mat6			{ $$.type = OT_ParamValue; memcpy($$.value.matrixValue, $2, sizeof($2)); }
-	;
-
-param_body_mat8
-	: /* empty */		{ $$.type = OT_None; }
-	| '=' mat8			{ $$.type = OT_ParamValue; memcpy($$.value.matrixValue, $2, sizeof($2)); }
-	;
-
-param_body_mat9
-	: /* empty */		{ $$.type = OT_None; }
-	| '=' mat9			{ $$.type = OT_ParamValue; memcpy($$.value.matrixValue, $2, sizeof($2)); }
-	;
-
-param_body_mat12
-	: /* empty */		{ $$.type = OT_None; }
-	| '=' mat12			{ $$.type = OT_ParamValue; memcpy($$.value.matrixValue, $2, sizeof($2)); }
-	;
-
-param_body_mat16
-	: /* empty */		{ $$.type = OT_None; }
-	| '=' mat16			{ $$.type = OT_ParamValue; memcpy($$.value.matrixValue, $2, sizeof($2)); }
-	;
-
-param_body_sampler
-	: /* empty */		{ $$.type = OT_None; }
-	| '=' '{' sampler_state_body '}' { }
-	;
-
-param_body_tex
-	: /* empty */		{ $$.type = OT_None; }
-	| '=' TOKEN_STRING	{ $$.type = OT_ParamStrValue; $$.value.strValue = $2; }
-	;
-
-	/* Blocks */
-blocks
-	: blocks_header '{' blocks_body '}' ';' { nodePop(parse_state); $$ = $1; }
-	;
-
-blocks_header
-	: TOKEN_BLOCKS '='
-		{ 
-			$$ = nodeCreate(parse_state->memContext, NT_Blocks); 
-			nodePush(parse_state, $$);
-		}
-	;
-
-blocks_body
-	: /* empty */
-	| block blocks_body		{ nodeOptionsAdd(parse_state->memContext, parse_state->topNode->options, &$1); }
-	;
-
-block
-	: block_header qualifier_list ';' { nodePop(parse_state); $$.type = OT_Block; $$.value.nodePtr = $1; }
-	;
-
-block_header
-	: TOKEN_PARAMSBLOCK TOKEN_IDENTIFIER
-		{
-			$$ = nodeCreate(parse_state->memContext, NT_Block);
-			nodePush(parse_state, $$);
-
-			NodeOption blockName;
-			blockName.type = OT_Identifier;
-			blockName.value.strValue = $2;
-
-			nodeOptionsAdd(parse_state->memContext, parse_state->topNode->options, &blockName);
-		}
-	;
-
-	/* Qualifiers */
-qualifier_list
-	: /* empty */
-	| qualifier qualifier_list		{ nodeOptionsAdd(parse_state->memContext, parse_state->topNode->options, &$1); }
-	;
-
-qualifier
-	: ':' TOKEN_ALIAS '(' TOKEN_STRING ')'		{ $$.type = OT_Alias; $$.value.strValue = $4; }
-	| ':' TOKEN_AUTO '(' TOKEN_STRING ')'		{ $$.type = OT_Auto; $$.value.strValue = $4; }
-	| ':' TOKEN_SHARED '(' TOKEN_BOOLEAN ')'	{ $$.type = OT_Shared; $$.value.intValue = $4; }
-	| ':' TOKEN_USAGE '(' TOKEN_BUFFERUSAGE ')'	{ $$.type = OT_Usage; $$.value.intValue = $4; }
-	;
-%%
-
-void yyerror(YYLTYPE *locp, ParseState* parse_state, yyscan_t scanner, const char *msg) 
-{ 
-	parse_state->hasError = 1;
-	parse_state->errorLine = locp->first_line;
-	parse_state->errorColumn = locp->first_column;
-	parse_state->errorMessage = mmalloc_strdup(parse_state->memContext, msg);
-	parse_state->errorFile = locp->filename;
+%{
+#include "BsParserFX.h"
+#include "BsLexerFX.h"
+#define inline
+
+void yyerror(YYLTYPE *locp, ParseState* parse_state, yyscan_t scanner, const char *msg);
+%}
+
+%code requires{
+#include "BsMMAlloc.h"
+#include "BsASTFX.h"
+#include "BsIncludeHandler.h"
+
+#ifndef YY_TYPEDEF_YY_SCANNER_T
+#define YY_TYPEDEF_YY_SCANNER_T
+	typedef void* yyscan_t;
+#endif
+
+typedef struct YYLTYPE {
+	int first_line;
+	int first_column;
+	int last_line;
+	int last_column;
+	char *filename;
+} YYLTYPE;
+#define YYLTYPE_IS_DECLARED 1
+
+#define YYLLOC_DEFAULT(Current, Rhs, N)																\
+	do																								\
+		if (N)																						\
+		{																							\
+			(Current).first_line = YYRHSLOC (Rhs, 1).first_line;									\
+			(Current).first_column = YYRHSLOC (Rhs, 1).first_column;								\
+			(Current).last_line = YYRHSLOC (Rhs, N).last_line;										\
+			(Current).last_column = YYRHSLOC (Rhs, N).last_column;									\
+			(Current).filename = YYRHSLOC (Rhs, 1).filename;										\
+		}																							\
+		else																						\
+		{																							\
+			(Current).first_line = (Current).last_line = YYRHSLOC (Rhs, 0).last_line;				\
+			(Current).first_column = (Current).last_column = YYRHSLOC (Rhs, 0).last_column;			\
+			(Current).filename = NULL;																\
+		}																							\
+	while (0)
+
+#define ADD_PARAMETER(OUTPUT, TYPE, NAME)															\
+			OUTPUT = nodeCreate(parse_state->memContext, NT_Parameter);								\
+			nodePush(parse_state, OUTPUT);															\
+																									\
+			NodeOption paramType;																	\
+			paramType.type = OT_ParamType;															\
+			paramType.value.intValue = TYPE;														\
+																									\
+			NodeOption paramName;																	\
+			paramName.type = OT_Identifier;															\
+			paramName.value.strValue = NAME;														\
+																									\
+			nodeOptionsAdd(parse_state->memContext, parse_state->topNode->options, &paramType);		\
+			nodeOptionsAdd(parse_state->memContext, parse_state->topNode->options, &paramName);		\
+
+}
+
+%output  "BsParserFX.c"
+%defines "BsParserFX.h"
+
+%define api.pure
+%locations
+%lex-param { yyscan_t scanner }
+%parse-param { ParseState* parse_state }
+%parse-param { yyscan_t scanner }
+%glr-parser
+
+%union {
+	int intValue;
+	float floatValue;
+	float matrixValue[16];
+	int intVectorValue[4];
+	const char* strValue;
+	ASTFXNode* nodePtr;
+	NodeOption nodeOption;
+}
+
+	/* Value types */
+%token <intValue>	TOKEN_INTEGER
+%token <floatValue> TOKEN_FLOAT
+%token <intValue>	TOKEN_BOOLEAN
+%token <strValue>	TOKEN_STRING
+%token <strValue>	TOKEN_IDENTIFIER
+
+%token <intValue>	TOKEN_FILLMODEVALUE
+%token <intValue>	TOKEN_CULLMODEVALUE
+%token <intValue>	TOKEN_COMPFUNCVALUE
+%token <intValue>	TOKEN_OPVALUE
+%token <intValue>	TOKEN_COLORMASK
+%token <intValue>	TOKEN_ADDRMODEVALUE
+%token <intValue>	TOKEN_FILTERVALUE
+%token <intValue>	TOKEN_BLENDOPVALUE
+%token <intValue>	TOKEN_BUFFERUSAGE
+
+%token <intValue> TOKEN_FLOATTYPE 
+%token <intValue> TOKEN_FLOAT2TYPE 
+%token <intValue> TOKEN_FLOAT3TYPE 
+%token <intValue> TOKEN_FLOAT4TYPE
+%token <intValue> TOKEN_INTTYPE 
+%token <intValue> TOKEN_INT2TYPE 
+%token <intValue> TOKEN_INT3TYPE 
+%token <intValue> TOKEN_INT4TYPE
+%token <intValue> TOKEN_COLORTYPE
+
+%token <intValue> TOKEN_MAT2x2TYPE 
+%token <intValue> TOKEN_MAT2x3TYPE 
+%token <intValue> TOKEN_MAT2x4TYPE
+
+%token <intValue> TOKEN_MAT3x2TYPE 
+%token <intValue> TOKEN_MAT3x3TYPE 
+%token <intValue> TOKEN_MAT3x4TYPE
+
+%token <intValue> TOKEN_MAT4x2TYPE 
+%token <intValue> TOKEN_MAT4x3TYPE 
+%token <intValue> TOKEN_MAT4x4TYPE
+
+%token <intValue> TOKEN_SAMPLER1D 
+%token <intValue> TOKEN_SAMPLER2D 
+%token <intValue> TOKEN_SAMPLER3D 
+%token <intValue> TOKEN_SAMPLERCUBE 
+%token <intValue> TOKEN_SAMPLER2DMS
+
+%token <intValue> TOKEN_TEXTURE1D 
+%token <intValue> TOKEN_TEXTURE2D 
+%token <intValue> TOKEN_TEXTURE3D 
+%token <intValue> TOKEN_TEXTURECUBE 
+%token <intValue> TOKEN_TEXTURE2DMS
+
+%token <intValue> TOKEN_BYTEBUFFER 
+%token <intValue> TOKEN_STRUCTBUFFER 
+%token <intValue> TOKEN_RWTYPEDBUFFER 
+%token <intValue> TOKEN_RWBYTEBUFFER
+%token <intValue> TOKEN_RWSTRUCTBUFFER 
+%token <intValue> TOKEN_RWAPPENDBUFFER 
+%token <intValue> TOKEN_RWCONSUMEBUFFER
+
+%token TOKEN_PARAMSBLOCK
+
+	/* Qualifiers */
+%token TOKEN_AUTO TOKEN_ALIAS TOKEN_SHARED TOKEN_USAGE
+
+	/* Shader keywords */
+%token TOKEN_SEPARABLE TOKEN_QUEUE TOKEN_PRIORITY TOKEN_TRANSPARENT
+%token TOKEN_PARAMETERS TOKEN_BLOCKS TOKEN_TECHNIQUE
+
+	/* Technique keywords */
+%token	TOKEN_RENDERER TOKEN_LANGUAGE TOKEN_PASS
+
+	/* Pass keywords */
+%token	TOKEN_VERTEX TOKEN_FRAGMENT TOKEN_GEOMETRY TOKEN_HULL TOKEN_DOMAIN TOKEN_COMPUTE TOKEN_COMMON
+%token	TOKEN_STENCILREF
+
+%token	TOKEN_FILLMODE TOKEN_CULLMODE TOKEN_DEPTHBIAS TOKEN_SDEPTHBIAS
+%token	TOKEN_DEPTHCLIP TOKEN_SCISSOR TOKEN_MULTISAMPLE TOKEN_AALINE
+
+%token	TOKEN_DEPTHREAD TOKEN_DEPTHWRITE TOKEN_COMPAREFUNC TOKEN_STENCIL
+%token	TOKEN_STENCILREADMASK TOKEN_STENCILWRITEMASK TOKEN_STENCILOPFRONT TOKEN_STENCILOPBACK
+%token	TOKEN_FAIL TOKEN_ZFAIL
+
+%token	TOKEN_ALPHATOCOVERAGE TOKEN_INDEPENDANTBLEND TOKEN_TARGET TOKEN_INDEX
+%token	TOKEN_BLEND TOKEN_COLOR TOKEN_ALPHA TOKEN_WRITEMASK
+%token	TOKEN_SOURCE TOKEN_DEST TOKEN_OP
+
+	/* Sampler state keywords */
+%token	TOKEN_ADDRMODE TOKEN_MINFILTER TOKEN_MAGFILTER TOKEN_MIPFILTER
+%token	TOKEN_MAXANISO TOKEN_MIPBIAS TOKEN_MIPMIN TOKEN_MIPMAX
+%token	TOKEN_BORDERCOLOR TOKEN_U TOKEN_V TOKEN_W
+
+%type <nodePtr>		shader;
+%type <nodeOption>	shader_statement;
+%type <nodeOption>	shader_option;
+
+%type <nodePtr>		technique;
+%type <nodePtr>		technique_header;
+%type <nodeOption>	technique_statement;
+%type <nodeOption>	technique_option;
+
+%type <nodePtr>		pass;
+%type <nodePtr>		pass_header;
+%type <nodeOption>	pass_statement;
+%type <nodeOption>	pass_option;
+
+%type <nodePtr>		code;
+%type <nodePtr>		code_header;
+
+%type <nodePtr>		stencil_op_front_header;
+%type <nodePtr>		stencil_op_back_header;
+%type <nodeOption>	stencil_op_option;
+
+%type <nodePtr>		target;
+%type <nodePtr>		target_header;
+%type <nodeOption>	target_statement;
+%type <nodeOption>	target_option;
+
+%type <nodePtr>		blend_color_header;
+%type <nodePtr>		blend_alpha_header;
+%type <nodeOption>	blenddef_option;
+
+%type <nodeOption>	sampler_state_option;
+
+%type <nodePtr>		addr_mode;
+%type <nodePtr>		addr_mode_header;
+%type <nodeOption>	addr_mode_option;
+
+%type <nodePtr> parameters
+%type <nodePtr> parameters_header
+%type <nodeOption> parameter
+
+%type <nodePtr> block_header
+%type <nodeOption> block
+%type <nodePtr> blocks_header
+%type <nodePtr> blocks
+
+%type <nodeOption> qualifier
+
+%type <matrixValue> float2;
+%type <matrixValue> float3;
+%type <matrixValue> float4;
+%type <intVectorValue> int2;
+%type <intVectorValue> int3;
+%type <intVectorValue> int4;
+%type <matrixValue> mat6;
+%type <matrixValue> mat8;
+%type <matrixValue> mat9;
+%type <matrixValue> mat12;
+%type <matrixValue> mat16;
+
+%type <nodePtr> param_header_float
+%type <nodePtr> param_header_float2
+%type <nodePtr> param_header_float3
+%type <nodePtr> param_header_float4
+%type <nodePtr> param_header_int
+%type <nodePtr> param_header_int2
+%type <nodePtr> param_header_int3
+%type <nodePtr> param_header_int4
+%type <nodePtr> param_header_color
+%type <nodePtr> param_header_mat2x2
+%type <nodePtr> param_header_mat2x3
+%type <nodePtr> param_header_mat2x4
+%type <nodePtr> param_header_mat3x2
+%type <nodePtr> param_header_mat3x3
+%type <nodePtr> param_header_mat3x4
+%type <nodePtr> param_header_mat4x2
+%type <nodePtr> param_header_mat4x3
+%type <nodePtr> param_header_mat4x4
+%type <nodePtr> param_header_sampler
+%type <nodePtr> param_header_texture
+%type <nodePtr> param_header_buffer
+%type <nodePtr> param_header_qualified_sampler
+
+%type <nodeOption> param_body_float
+%type <nodeOption> param_body_float2
+%type <nodeOption> param_body_float3
+%type <nodeOption> param_body_float4
+%type <nodeOption> param_body_int
+%type <nodeOption> param_body_int2
+%type <nodeOption> param_body_int3
+%type <nodeOption> param_body_int4
+%type <nodeOption> param_body_mat6
+%type <nodeOption> param_body_mat8
+%type <nodeOption> param_body_mat9
+%type <nodeOption> param_body_mat12
+%type <nodeOption> param_body_mat16
+%type <nodeOption> param_body_sampler
+%type <nodeOption> param_body_tex
+
+%%
+
+	/* Shader */
+
+shader
+	: /* empty */				{ }
+	| shader_statement shader	{ nodeOptionsAdd(parse_state->memContext, parse_state->topNode->options, &$1); }
+	;
+
+shader_statement
+	: shader_option
+	| technique			{ $$.type = OT_Technique; $$.value.nodePtr = $1; }
+	| parameters		{ $$.type = OT_Parameters; $$.value.nodePtr = $1; }
+	| blocks			{ $$.type = OT_Blocks; $$.value.nodePtr = $1; }
+	;
+
+shader_option
+	: TOKEN_SEPARABLE '=' TOKEN_BOOLEAN ';'		{ $$.type = OT_Separable; $$.value.intValue = $3; }
+	| TOKEN_QUEUE '=' TOKEN_INTEGER ';'			{ $$.type = OT_Queue; $$.value.intValue = $3; }
+	| TOKEN_PRIORITY '=' TOKEN_INTEGER ';'		{ $$.type = OT_Priority; $$.value.intValue = $3; }
+	| TOKEN_TRANSPARENT '=' TOKEN_BOOLEAN ';'	{ $$.type = OT_Transparent; $$.value.intValue = $3; }
+	;
+
+	/* Technique */
+
+technique
+	: technique_header '{' technique_body '}' ';' { nodePop(parse_state); $$ = $1; }
+	;
+
+technique_header
+	: TOKEN_TECHNIQUE '=' 
+		{ 
+			$$ = nodeCreate(parse_state->memContext, NT_Technique); 
+			nodePush(parse_state, $$);
+		}
+	;
+
+technique_body
+	: /* empty */
+	| technique_statement technique_body		{ nodeOptionsAdd(parse_state->memContext, parse_state->topNode->options, &$1); }
+	;
+
+technique_statement
+	: technique_option
+	| pass				{ $$.type = OT_Pass; $$.value.nodePtr = $1; }
+	| pass_option
+	| code				{ $$.type = OT_Code; $$.value.nodePtr = $1; }
+	;
+
+technique_option
+	: TOKEN_RENDERER '=' TOKEN_STRING ';'	{ $$.type = OT_Renderer; $$.value.strValue = $3; }
+	| TOKEN_LANGUAGE '=' TOKEN_STRING ';'	{ $$.type = OT_Language; $$.value.strValue = $3; }
+	;
+
+	/* Pass */
+
+pass
+	: pass_header '{' pass_body '}' ';' { nodePop(parse_state); $$ = $1; }
+	;
+
+pass_header
+	: TOKEN_PASS '=' 
+		{ 
+			$$ = nodeCreate(parse_state->memContext, NT_Pass); 
+			nodePush(parse_state, $$);
+		}
+	;
+
+pass_body
+	: /* empty */
+	| pass_statement pass_body		{ nodeOptionsAdd(parse_state->memContext, parse_state->topNode->options, &$1); }
+	;
+
+pass_statement
+	: pass_option
+	| code				{ $$.type = OT_Code; $$.value.nodePtr = $1; }
+	;
+
+pass_option
+	: TOKEN_INDEX '=' TOKEN_INTEGER ';'							{ $$.type = OT_Index; $$.value.intValue = $3; }
+	| TOKEN_FILLMODE '=' TOKEN_FILLMODEVALUE ';'				{ $$.type = OT_FillMode; $$.value.intValue = $3; }
+	| TOKEN_CULLMODE '=' TOKEN_CULLMODEVALUE ';'				{ $$.type = OT_CullMode; $$.value.intValue = $3; }
+	| TOKEN_DEPTHBIAS '=' TOKEN_FLOAT ';'						{ $$.type = OT_DepthBias; $$.value.floatValue = $3; }
+	| TOKEN_SDEPTHBIAS '=' TOKEN_FLOAT ';'						{ $$.type = OT_SDepthBias; $$.value.floatValue = $3; }
+	| TOKEN_DEPTHCLIP '=' TOKEN_BOOLEAN ';'						{ $$.type = OT_DepthClip; $$.value.intValue = $3; }
+	| TOKEN_SCISSOR '=' TOKEN_BOOLEAN ';'						{ $$.type = OT_Scissor; $$.value.intValue = $3; }
+	| TOKEN_MULTISAMPLE '=' TOKEN_BOOLEAN ';'					{ $$.type = OT_Multisample; $$.value.intValue = $3; }
+	| TOKEN_AALINE '=' TOKEN_BOOLEAN ';'						{ $$.type = OT_AALine; $$.value.intValue = $3; }
+	| TOKEN_DEPTHREAD '=' TOKEN_BOOLEAN ';'						{ $$.type = OT_DepthRead; $$.value.intValue = $3; }
+	| TOKEN_DEPTHWRITE '=' TOKEN_BOOLEAN ';'					{ $$.type = OT_DepthWrite; $$.value.intValue = $3; }
+	| TOKEN_COMPAREFUNC '=' TOKEN_COMPFUNCVALUE ';'				{ $$.type = OT_CompareFunc; $$.value.intValue = $3; }
+	| TOKEN_STENCIL '=' TOKEN_BOOLEAN ';'						{ $$.type = OT_Stencil; $$.value.intValue = $3; }
+	| TOKEN_STENCILREADMASK '=' TOKEN_INTEGER ';'				{ $$.type = OT_StencilReadMask; $$.value.intValue = $3; }
+	| TOKEN_STENCILWRITEMASK '=' TOKEN_INTEGER ';'				{ $$.type = OT_StencilWriteMask; $$.value.intValue = $3; }
+	| stencil_op_front_header '{' stencil_op_body '}' ';'		{ nodePop(parse_state); $$.type = OT_StencilOpFront; $$.value.nodePtr = $1; }
+	| stencil_op_back_header '{' stencil_op_body '}' ';'		{ nodePop(parse_state); $$.type = OT_StencilOpBack; $$.value.nodePtr = $1; }
+	| stencil_op_front_header '{' stencil_op_body_init '}' ';'	{ nodePop(parse_state); $$.type = OT_StencilOpFront; $$.value.nodePtr = $1; }
+	| stencil_op_back_header '{' stencil_op_body_init '}' ';'	{ nodePop(parse_state); $$.type = OT_StencilOpBack; $$.value.nodePtr = $1; }
+	| TOKEN_ALPHATOCOVERAGE '=' TOKEN_BOOLEAN ';'				{ $$.type = OT_AlphaToCoverage; $$.value.intValue = $3; }
+	| TOKEN_INDEPENDANTBLEND '=' TOKEN_BOOLEAN ';'				{ $$.type = OT_IndependantBlend; $$.value.intValue = $3; }
+	| target													{ $$.type = OT_Target; $$.value.nodePtr = $1; }
+	| TOKEN_STENCILREF '=' TOKEN_INTEGER ';'					{ $$.type = OT_StencilRef; $$.value.intValue = $3; }
+	;
+
+	/* Code blocks */
+
+code
+	: code_header '{' TOKEN_INDEX '=' TOKEN_INTEGER ';' '}' ';'
+	{
+		NodeOption index;
+		index.type = OT_Index; 
+		index.value.intValue = $5;
+
+		nodeOptionsAdd(parse_state->memContext, parse_state->topNode->options, &index);
+
+		nodePop(parse_state); 
+		$$ = $1;
+	}
+	;
+
+code_header
+	: TOKEN_VERTEX '='
+		{ 
+			$$ = nodeCreate(parse_state->memContext, NT_CodeVertex); 
+			nodePush(parse_state, $$);
+		}
+	| TOKEN_FRAGMENT '='
+		{ 
+			$$ = nodeCreate(parse_state->memContext, NT_CodeFragment); 
+			nodePush(parse_state, $$);
+		}
+	| TOKEN_GEOMETRY '='
+		{ 
+			$$ = nodeCreate(parse_state->memContext, NT_CodeGeometry); 
+			nodePush(parse_state, $$);
+		}
+	| TOKEN_HULL '='
+		{ 
+			$$ = nodeCreate(parse_state->memContext, NT_CodeHull); 
+			nodePush(parse_state, $$);
+		}
+	| TOKEN_DOMAIN '='
+		{ 
+			$$ = nodeCreate(parse_state->memContext, NT_CodeDomain); 
+			nodePush(parse_state, $$);
+		}
+	| TOKEN_COMPUTE '='
+		{ 
+			$$ = nodeCreate(parse_state->memContext, NT_CodeCompute); 
+			nodePush(parse_state, $$);
+		}
+	| TOKEN_COMMON '='
+		{ 
+			$$ = nodeCreate(parse_state->memContext, NT_CodeCommon); 
+			nodePush(parse_state, $$);
+		}
+	;
+
+	/* Stencil op */
+
+stencil_op_front_header
+	: TOKEN_STENCILOPFRONT '='
+		{ 
+			$$ = nodeCreate(parse_state->memContext, NT_StencilOp); 
+			nodePush(parse_state, $$);
+		}
+	;
+
+stencil_op_back_header
+	: TOKEN_STENCILOPBACK '='
+		{ 
+			$$ = nodeCreate(parse_state->memContext, NT_StencilOp); 
+			nodePush(parse_state, $$);
+		}
+	;
+
+stencil_op_body_init
+	: TOKEN_OPVALUE ',' TOKEN_OPVALUE ',' TOKEN_OPVALUE ',' TOKEN_COMPFUNCVALUE
+		{
+			NodeOption fail; fail.type = OT_Fail; fail.value.intValue = $1;
+			NodeOption zfail; zfail.type = OT_ZFail; zfail.value.intValue = $3;
+			NodeOption pass; pass.type = OT_PassOp; pass.value.intValue = $5;
+			NodeOption cmp; cmp.type = OT_CompareFunc; cmp.value.intValue = $7;
+
+			nodeOptionsAdd(parse_state->memContext, parse_state->topNode->options, &fail);
+			nodeOptionsAdd(parse_state->memContext, parse_state->topNode->options, &zfail);
+			nodeOptionsAdd(parse_state->memContext, parse_state->topNode->options, &pass);
+			nodeOptionsAdd(parse_state->memContext, parse_state->topNode->options, &cmp);
+		}
+	;
+
+stencil_op_body
+	: /* empty */
+	| stencil_op_option stencil_op_body		{ nodeOptionsAdd(parse_state->memContext, parse_state->topNode->options, &$1); }
+	;
+
+stencil_op_option
+	: TOKEN_FAIL '=' TOKEN_OPVALUE ';'					{ $$.type = OT_Fail; $$.value.intValue = $3; }
+	| TOKEN_ZFAIL '=' TOKEN_OPVALUE ';'					{ $$.type = OT_ZFail; $$.value.intValue = $3; }
+	| TOKEN_PASS '=' TOKEN_OPVALUE ';'					{ $$.type = OT_PassOp; $$.value.intValue = $3; }
+	| TOKEN_COMPAREFUNC '=' TOKEN_COMPFUNCVALUE ';'		{ $$.type = OT_CompareFunc; $$.value.intValue = $3; }
+	; 
+
+	/* Target */
+target
+	: target_header '{' target_body '}' ';' { nodePop(parse_state); $$ = $1; }
+	;
+
+target_header
+	: TOKEN_TARGET '='
+		{ 
+			$$ = nodeCreate(parse_state->memContext, NT_Target); 
+			nodePush(parse_state, $$);
+		}
+	;
+
+target_body
+	: /* empty */
+	| target_statement target_body		{ nodeOptionsAdd(parse_state->memContext, parse_state->topNode->options, &$1); }
+	;
+
+target_statement
+	: target_option
+	;
+
+target_option
+	: TOKEN_INDEX '=' TOKEN_INTEGER ';'					{ $$.type = OT_Index; $$.value.intValue = $3; }
+	| TOKEN_BLEND '=' TOKEN_BOOLEAN ';'					{ $$.type = OT_Blend; $$.value.intValue = $3; }
+	| blend_color_header '{' blenddef_body '}' ';'		{ nodePop(parse_state); $$.type = OT_Color; $$.value.nodePtr = $1; }
+	| blend_alpha_header '{' blenddef_body '}' ';'		{ nodePop(parse_state); $$.type = OT_Alpha; $$.value.nodePtr = $1; }
+	| blend_color_header '{' blenddef_body_init '}' ';'		{ nodePop(parse_state); $$.type = OT_Color; $$.value.nodePtr = $1; }
+	| blend_alpha_header '{' blenddef_body_init '}' ';'		{ nodePop(parse_state); $$.type = OT_Alpha; $$.value.nodePtr = $1; }
+	| TOKEN_WRITEMASK '=' TOKEN_COLORMASK ';'			{ $$.type = OT_WriteMask; $$.value.intValue = $3; }
+	;
+
+	/* Blend definition */
+blend_color_header
+	: TOKEN_COLOR '='
+		{ 
+			$$ = nodeCreate(parse_state->memContext, NT_BlendDef); 
+			nodePush(parse_state, $$);
+		}
+	;
+
+blend_alpha_header
+	: TOKEN_ALPHA '='
+		{ 
+			$$ = nodeCreate(parse_state->memContext, NT_BlendDef); 
+			nodePush(parse_state, $$);
+		}
+	;
+
+blenddef_body
+	: /* empty */
+	| blenddef_option blenddef_body		{ nodeOptionsAdd(parse_state->memContext, parse_state->topNode->options, &$1); }
+	;
+
+blenddef_body_init
+	: TOKEN_OPVALUE ',' TOKEN_OPVALUE ',' TOKEN_BLENDOPVALUE
+		{
+			NodeOption src; src.type = OT_Source; src.value.intValue = $1;
+			NodeOption dst; dst.type = OT_Dest; dst.value.intValue = $3;
+			NodeOption op; op.type = OT_Op; op.value.intValue = $5;
+
+			nodeOptionsAdd(parse_state->memContext, parse_state->topNode->options, &src);
+			nodeOptionsAdd(parse_state->memContext, parse_state->topNode->options, &dst);
+			nodeOptionsAdd(parse_state->memContext, parse_state->topNode->options, &op);
+		}
+	;
+
+blenddef_option
+	: TOKEN_SOURCE '=' TOKEN_OPVALUE ';'					{ $$.type = OT_Source; $$.value.intValue = $3; }
+	| TOKEN_DEST '=' TOKEN_OPVALUE ';'						{ $$.type = OT_Dest; $$.value.intValue = $3; }
+	| TOKEN_OP '=' TOKEN_BLENDOPVALUE ';'					{ $$.type = OT_Op; $$.value.intValue = $3; }
+	;
+
+	/* Sampler state */
+
+sampler_state_body
+	: /* empty */
+	| sampler_state_option sampler_state_body		{ nodeOptionsAdd(parse_state->memContext, parse_state->topNode->options, &$1); }
+	;
+
+sampler_state_option
+	: addr_mode												{ $$.type = OT_AddrMode; $$.value.nodePtr = $1; }
+	| TOKEN_MINFILTER '=' TOKEN_FILTERVALUE ';'				{ $$.type = OT_MinFilter; $$.value.intValue = $3; }
+	| TOKEN_MAGFILTER '=' TOKEN_FILTERVALUE ';'				{ $$.type = OT_MagFilter; $$.value.intValue = $3; }
+	| TOKEN_MIPFILTER '=' TOKEN_FILTERVALUE ';'				{ $$.type = OT_MipFilter; $$.value.intValue = $3; }
+	| TOKEN_MAXANISO '=' TOKEN_INTEGER ';'					{ $$.type = OT_MaxAniso; $$.value.intValue = $3; }
+	| TOKEN_MIPBIAS '=' TOKEN_FLOAT ';'						{ $$.type = OT_MipBias; $$.value.floatValue = $3; }
+	| TOKEN_MIPMIN '=' TOKEN_FLOAT ';'						{ $$.type = OT_MipMin; $$.value.floatValue = $3; }
+	| TOKEN_MIPMAX '=' TOKEN_FLOAT ';'						{ $$.type = OT_MipMax; $$.value.floatValue = $3; }
+	| TOKEN_BORDERCOLOR '=' float4 ';'						{ $$.type = OT_BorderColor; memcpy($$.value.matrixValue, $3, sizeof($3)); }
+	| TOKEN_COMPAREFUNC '=' TOKEN_COMPFUNCVALUE ';'			{ $$.type = OT_CompareFunc; $$.value.intValue = $3; }
+	;
+
+	/* Addresing mode */
+addr_mode
+	: addr_mode_header '{' addr_mode_body '}' ';'		{ nodePop(parse_state); $$ = $1; }
+	| addr_mode_header '{' addr_mode_body_init '}' ';'	{ nodePop(parse_state); $$ = $1; }
+	;
+
+addr_mode_header
+	: TOKEN_ADDRMODE '='
+		{ 
+			$$ = nodeCreate(parse_state->memContext, NT_AddrMode); 
+			nodePush(parse_state, $$);
+		}
+	;
+
+addr_mode_body_init
+	: TOKEN_ADDRMODEVALUE ',' TOKEN_ADDRMODEVALUE ',' TOKEN_ADDRMODEVALUE
+		{
+			NodeOption u; u.type = OT_U; u.value.intValue = $1;
+			NodeOption v; v.type = OT_V; v.value.intValue = $3;
+			NodeOption w; w.type = OT_W; w.value.intValue = $5;
+
+			nodeOptionsAdd(parse_state->memContext, parse_state->topNode->options, &u);
+			nodeOptionsAdd(parse_state->memContext, parse_state->topNode->options, &v);
+			nodeOptionsAdd(parse_state->memContext, parse_state->topNode->options, &w);
+		}
+	;
+
+addr_mode_body
+	: /* empty */
+	| addr_mode_option addr_mode_body		{ nodeOptionsAdd(parse_state->memContext, parse_state->topNode->options, &$1); }
+	;
+
+addr_mode_option
+	: TOKEN_U '=' TOKEN_ADDRMODEVALUE ';'					{ $$.type = OT_U; $$.value.intValue = $3; }
+	| TOKEN_V '=' TOKEN_ADDRMODEVALUE ';'					{ $$.type = OT_V; $$.value.intValue = $3; }
+	| TOKEN_W '=' TOKEN_ADDRMODEVALUE ';'					{ $$.type = OT_W; $$.value.intValue = $3; }
+	;
+
+	/* Value types */
+float2
+	: '{' TOKEN_FLOAT ',' TOKEN_FLOAT '}'	{ $$[0] = $2; $$[1] = $4; }
+	;
+
+float3
+	: '{' TOKEN_FLOAT ',' TOKEN_FLOAT ',' TOKEN_FLOAT '}'	{ $$[0] = $2; $$[1] = $4; $$[2] = $6; }
+	;
+
+float4
+	: '{' TOKEN_FLOAT ',' TOKEN_FLOAT ',' TOKEN_FLOAT ',' TOKEN_FLOAT '}'	{ $$[0] = $2; $$[1] = $4; $$[2] = $6; $$[3] = $8;}
+	;
+
+int2
+	: '{' TOKEN_INTEGER ',' TOKEN_INTEGER '}'	{ $$[0] = $2; $$[1] = $4; }
+	;
+
+int3
+	: '{' TOKEN_INTEGER ',' TOKEN_INTEGER ',' TOKEN_INTEGER '}'	{ $$[0] = $2; $$[1] = $4; $$[2] = $6; }
+	;
+
+int4
+	: '{' TOKEN_INTEGER ',' TOKEN_INTEGER ',' TOKEN_INTEGER ',' TOKEN_INTEGER '}'	{ $$[0] = $2; $$[1] = $4; $$[2] = $6; $$[3] = $8;}
+	;
+
+mat6
+	: '{' TOKEN_FLOAT ',' TOKEN_FLOAT ',' TOKEN_FLOAT ',' 
+		  TOKEN_FLOAT ',' TOKEN_FLOAT ',' TOKEN_FLOAT '}'	
+		{ 
+			$$[0] = $2; $$[1] = $4; $$[2] = $6; 
+			$$[3] = $8; $$[4] = $10; $$[5] = $12;
+		}
+	;
+
+mat8
+	: '{' TOKEN_FLOAT ',' TOKEN_FLOAT ',' TOKEN_FLOAT ',' 
+		  TOKEN_FLOAT ',' TOKEN_FLOAT ',' TOKEN_FLOAT ',' 
+		  TOKEN_FLOAT ',' TOKEN_FLOAT '}'	
+		{ 
+			$$[0] = $2; $$[1] = $4; $$[2] = $6; 
+			$$[3] = $8; $$[4] = $10; $$[5] = $12;
+			$$[6] = $14; $$[7] = $16;
+		}
+	;
+
+mat9
+	: '{' TOKEN_FLOAT ',' TOKEN_FLOAT ',' TOKEN_FLOAT ',' 
+		  TOKEN_FLOAT ',' TOKEN_FLOAT ',' TOKEN_FLOAT ',' 
+		  TOKEN_FLOAT ',' TOKEN_FLOAT ',' TOKEN_FLOAT '}'	
+		{ 
+			$$[0] = $2; $$[1] = $4; $$[2] = $6; 
+			$$[3] = $8; $$[4] = $10; $$[5] = $12;
+			$$[6] = $14; $$[7] = $16; $$[8] = $18;
+		}
+	;
+
+mat12
+	: '{' TOKEN_FLOAT ',' TOKEN_FLOAT ',' TOKEN_FLOAT ',' TOKEN_FLOAT ',' 
+		  TOKEN_FLOAT ',' TOKEN_FLOAT ',' TOKEN_FLOAT ',' TOKEN_FLOAT ',' 
+		  TOKEN_FLOAT ',' TOKEN_FLOAT ',' TOKEN_FLOAT ',' TOKEN_FLOAT '}'	
+		{ 
+			$$[0] = $2; $$[1] = $4; $$[2] = $6; $$[3] = $8; 
+			$$[4] = $10; $$[5] = $12; $$[6] = $14; $$[7] = $16; 
+			$$[8] = $18; $$[9] = $20; $$[10] = $22; $$[11] = $24;
+		}
+	;
+
+mat16
+	: '{' TOKEN_FLOAT ',' TOKEN_FLOAT ',' TOKEN_FLOAT ',' TOKEN_FLOAT ',' 
+		  TOKEN_FLOAT ',' TOKEN_FLOAT ',' TOKEN_FLOAT ',' TOKEN_FLOAT ',' 
+		  TOKEN_FLOAT ',' TOKEN_FLOAT ',' TOKEN_FLOAT ',' TOKEN_FLOAT ',' 
+		  TOKEN_FLOAT ',' TOKEN_FLOAT ',' TOKEN_FLOAT ',' TOKEN_FLOAT '}'	
+		{ 
+			$$[0] = $2; $$[1] = $4; $$[2] = $6; $$[3] = $8; 
+			$$[4] = $10; $$[5] = $12; $$[6] = $14; $$[7] = $16; 
+			$$[8] = $18; $$[9] = $20; $$[10] = $22; $$[11] = $24;
+			$$[12] = $26; $$[13] = $28; $$[14] = $30; $$[15] = $32;
+		}
+	;
+
+	/* Parameters */
+parameters
+	: parameters_header '{' parameters_body '}' ';' { nodePop(parse_state); $$ = $1; }
+	;
+
+parameters_header
+	: TOKEN_PARAMETERS '='
+		{ 
+			$$ = nodeCreate(parse_state->memContext, NT_Parameters); 
+			nodePush(parse_state, $$);
+		}
+	;
+
+parameters_body
+	: /* empty */
+	| parameter parameters_body		{ nodeOptionsAdd(parse_state->memContext, parse_state->topNode->options, &$1); }
+	;
+
+parameter
+	: param_header_float	qualifier_list param_body_float		';' { nodeOptionsAdd(parse_state->memContext, parse_state->topNode->options, &$3); nodePop(parse_state); $$.type = OT_Parameter; $$.value.nodePtr = $1; }
+	| param_header_float2	qualifier_list param_body_float2	';' { nodeOptionsAdd(parse_state->memContext, parse_state->topNode->options, &$3); nodePop(parse_state); $$.type = OT_Parameter; $$.value.nodePtr = $1; }
+	| param_header_float3	qualifier_list param_body_float3	';' { nodeOptionsAdd(parse_state->memContext, parse_state->topNode->options, &$3); nodePop(parse_state); $$.type = OT_Parameter; $$.value.nodePtr = $1; }
+	| param_header_float4	qualifier_list param_body_float4	';' { nodeOptionsAdd(parse_state->memContext, parse_state->topNode->options, &$3); nodePop(parse_state); $$.type = OT_Parameter; $$.value.nodePtr = $1; }
+	| param_header_int		qualifier_list param_body_int		';' { nodeOptionsAdd(parse_state->memContext, parse_state->topNode->options, &$3); nodePop(parse_state); $$.type = OT_Parameter; $$.value.nodePtr = $1; }
+	| param_header_int2		qualifier_list param_body_int2		';' { nodeOptionsAdd(parse_state->memContext, parse_state->topNode->options, &$3); nodePop(parse_state); $$.type = OT_Parameter; $$.value.nodePtr = $1; }
+	| param_header_int3		qualifier_list param_body_int3		';' { nodeOptionsAdd(parse_state->memContext, parse_state->topNode->options, &$3); nodePop(parse_state); $$.type = OT_Parameter; $$.value.nodePtr = $1; }
+	| param_header_int4		qualifier_list param_body_int4		';' { nodeOptionsAdd(parse_state->memContext, parse_state->topNode->options, &$3); nodePop(parse_state); $$.type = OT_Parameter; $$.value.nodePtr = $1; }
+	| param_header_color	qualifier_list param_body_float4	';' { nodeOptionsAdd(parse_state->memContext, parse_state->topNode->options, &$3); nodePop(parse_state); $$.type = OT_Parameter; $$.value.nodePtr = $1; }
+	| param_header_mat2x2	qualifier_list param_body_float4	';' { nodeOptionsAdd(parse_state->memContext, parse_state->topNode->options, &$3); nodePop(parse_state); $$.type = OT_Parameter; $$.value.nodePtr = $1; }
+	| param_header_mat2x3	qualifier_list param_body_mat6		';' { nodeOptionsAdd(parse_state->memContext, parse_state->topNode->options, &$3); nodePop(parse_state); $$.type = OT_Parameter; $$.value.nodePtr = $1; }
+	| param_header_mat2x4	qualifier_list param_body_mat8		';' { nodeOptionsAdd(parse_state->memContext, parse_state->topNode->options, &$3); nodePop(parse_state); $$.type = OT_Parameter; $$.value.nodePtr = $1; }
+	| param_header_mat3x2	qualifier_list param_body_mat6		';' { nodeOptionsAdd(parse_state->memContext, parse_state->topNode->options, &$3); nodePop(parse_state); $$.type = OT_Parameter; $$.value.nodePtr = $1; }
+	| param_header_mat3x3	qualifier_list param_body_mat9		';' { nodeOptionsAdd(parse_state->memContext, parse_state->topNode->options, &$3); nodePop(parse_state); $$.type = OT_Parameter; $$.value.nodePtr = $1; }
+	| param_header_mat3x4	qualifier_list param_body_mat12		';' { nodeOptionsAdd(parse_state->memContext, parse_state->topNode->options, &$3); nodePop(parse_state); $$.type = OT_Parameter; $$.value.nodePtr = $1; }
+	| param_header_mat4x2	qualifier_list param_body_mat8		';' { nodeOptionsAdd(parse_state->memContext, parse_state->topNode->options, &$3); nodePop(parse_state); $$.type = OT_Parameter; $$.value.nodePtr = $1; }
+	| param_header_mat4x3	qualifier_list param_body_mat12		';' { nodeOptionsAdd(parse_state->memContext, parse_state->topNode->options, &$3); nodePop(parse_state); $$.type = OT_Parameter; $$.value.nodePtr = $1; }
+	| param_header_mat4x4	qualifier_list param_body_mat16		';' { nodeOptionsAdd(parse_state->memContext, parse_state->topNode->options, &$3); nodePop(parse_state); $$.type = OT_Parameter; $$.value.nodePtr = $1; }
+	| param_header_texture	qualifier_list param_body_tex		';' { nodeOptionsAdd(parse_state->memContext, parse_state->topNode->options, &$3); nodePop(parse_state); $$.type = OT_Parameter; $$.value.nodePtr = $1; }
+	| param_header_buffer	qualifier_list						';' { nodePop(parse_state); $$.type = OT_Parameter; $$.value.nodePtr = $1; }
+	| param_header_qualified_sampler		param_body_sampler	';' 
+		{ 
+			nodePop(parse_state);
+
+			NodeOption samplerState;
+			samplerState.type = OT_SamplerState;
+			samplerState.value.nodePtr = $1;
+
+			nodeOptionsAdd(parse_state->memContext, parse_state->topNode->options, &samplerState); 
+
+			$$.type = OT_Parameter; $$.value.nodePtr = parse_state->topNode; 
+			nodePop(parse_state); 
+		}
+	;
+
+param_header_float 
+	: TOKEN_FLOATTYPE TOKEN_IDENTIFIER { ADD_PARAMETER($$, $1, $2); }
+	;
+
+param_header_float2
+	: TOKEN_FLOAT2TYPE TOKEN_IDENTIFIER { ADD_PARAMETER($$, $1, $2); }
+	;
+
+param_header_float3
+	: TOKEN_FLOAT3TYPE TOKEN_IDENTIFIER { ADD_PARAMETER($$, $1, $2); }
+	;
+
+param_header_float4 
+	: TOKEN_FLOAT4TYPE TOKEN_IDENTIFIER { ADD_PARAMETER($$, $1, $2); }
+	;
+
+param_header_int 
+	: TOKEN_INTTYPE TOKEN_IDENTIFIER { ADD_PARAMETER($$, $1, $2); }
+	;
+
+param_header_int2
+	: TOKEN_INT2TYPE TOKEN_IDENTIFIER { ADD_PARAMETER($$, $1, $2); }
+	;
+
+param_header_int3
+	: TOKEN_INT3TYPE TOKEN_IDENTIFIER { ADD_PARAMETER($$, $1, $2); }
+	;
+
+param_header_int4
+	: TOKEN_INT4TYPE TOKEN_IDENTIFIER { ADD_PARAMETER($$, $1, $2); }
+	;
+
+param_header_color
+	: TOKEN_COLORTYPE TOKEN_IDENTIFIER { ADD_PARAMETER($$, $1, $2); }
+	;
+
+param_header_mat2x2
+	: TOKEN_MAT2x2TYPE TOKEN_IDENTIFIER { ADD_PARAMETER($$, $1, $2); }
+	;
+
+param_header_mat2x3
+	: TOKEN_MAT2x3TYPE TOKEN_IDENTIFIER { ADD_PARAMETER($$, $1, $2); }
+	;
+
+param_header_mat2x4
+	: TOKEN_MAT2x4TYPE TOKEN_IDENTIFIER { ADD_PARAMETER($$, $1, $2); }
+	;
+
+param_header_mat3x2
+	: TOKEN_MAT3x2TYPE TOKEN_IDENTIFIER { ADD_PARAMETER($$, $1, $2); }
+	;
+
+param_header_mat3x3
+	: TOKEN_MAT3x3TYPE TOKEN_IDENTIFIER { ADD_PARAMETER($$, $1, $2); }
+	;
+
+param_header_mat3x4
+	: TOKEN_MAT3x4TYPE TOKEN_IDENTIFIER { ADD_PARAMETER($$, $1, $2); }
+	;
+
+param_header_mat4x2
+	: TOKEN_MAT4x2TYPE TOKEN_IDENTIFIER { ADD_PARAMETER($$, $1, $2); }
+	;
+
+param_header_mat4x3
+	: TOKEN_MAT4x3TYPE TOKEN_IDENTIFIER { ADD_PARAMETER($$, $1, $2); }
+	;
+
+param_header_mat4x4
+	: TOKEN_MAT4x4TYPE TOKEN_IDENTIFIER { ADD_PARAMETER($$, $1, $2); }
+	;
+
+param_header_sampler
+	: TOKEN_SAMPLER1D TOKEN_IDENTIFIER { ADD_PARAMETER($$, $1, $2); }
+	| TOKEN_SAMPLER2D TOKEN_IDENTIFIER { ADD_PARAMETER($$, $1, $2); }
+	| TOKEN_SAMPLER3D TOKEN_IDENTIFIER { ADD_PARAMETER($$, $1, $2); }
+	| TOKEN_SAMPLERCUBE TOKEN_IDENTIFIER { ADD_PARAMETER($$, $1, $2); }
+	| TOKEN_SAMPLER2DMS TOKEN_IDENTIFIER { ADD_PARAMETER($$, $1, $2); }
+	;
+
+param_header_texture
+	: TOKEN_TEXTURE1D		TOKEN_IDENTIFIER { ADD_PARAMETER($$, $1, $2); }
+	| TOKEN_TEXTURE2D		TOKEN_IDENTIFIER { ADD_PARAMETER($$, $1, $2); }
+	| TOKEN_TEXTURE3D		TOKEN_IDENTIFIER { ADD_PARAMETER($$, $1, $2); }
+	| TOKEN_TEXTURECUBE		TOKEN_IDENTIFIER { ADD_PARAMETER($$, $1, $2); }
+	| TOKEN_TEXTURE2DMS		TOKEN_IDENTIFIER { ADD_PARAMETER($$, $1, $2); }
+	;
+
+param_header_buffer
+	: TOKEN_BYTEBUFFER		TOKEN_IDENTIFIER { ADD_PARAMETER($$, $1, $2); }
+	| TOKEN_STRUCTBUFFER	TOKEN_IDENTIFIER { ADD_PARAMETER($$, $1, $2); }
+	| TOKEN_RWTYPEDBUFFER	TOKEN_IDENTIFIER { ADD_PARAMETER($$, $1, $2); }
+	| TOKEN_RWBYTEBUFFER	TOKEN_IDENTIFIER { ADD_PARAMETER($$, $1, $2); }
+	| TOKEN_RWSTRUCTBUFFER	TOKEN_IDENTIFIER { ADD_PARAMETER($$, $1, $2); }
+	| TOKEN_RWAPPENDBUFFER	TOKEN_IDENTIFIER { ADD_PARAMETER($$, $1, $2); }
+	| TOKEN_RWCONSUMEBUFFER TOKEN_IDENTIFIER { ADD_PARAMETER($$, $1, $2); }
+	;
+
+param_header_qualified_sampler
+	: param_header_sampler qualifier_list	
+		{ 
+			$$ = nodeCreate(parse_state->memContext, NT_SamplerState); 
+			nodePush(parse_state, $$);
+		}
+	;
+
+param_body_float 
+	: /* empty */		{ $$.type = OT_None; }
+	| '=' TOKEN_FLOAT	{ $$.type = OT_ParamValue; $$.value.floatValue = $2; }
+	;
+
+param_body_float2
+	: /* empty */		{ $$.type = OT_None; }
+	| '=' float2		{ $$.type = OT_ParamValue; memcpy($$.value.matrixValue, $2, sizeof($2)); }
+	;
+
+param_body_float3
+	: /* empty */		{ $$.type = OT_None; }
+	| '=' float3		{ $$.type = OT_ParamValue; memcpy($$.value.matrixValue, $2, sizeof($2)); }
+	;
+
+param_body_float4
+	: /* empty */		{ $$.type = OT_None; }
+	| '=' float4		{ $$.type = OT_ParamValue; memcpy($$.value.matrixValue, $2, sizeof($2)); }
+	;
+
+param_body_int
+	: /* empty */		{ $$.type = OT_None; }
+	| '=' TOKEN_INTEGER	{ $$.type = OT_ParamValue; $$.value.intValue = $2; }
+	;
+
+param_body_int2
+	: /* empty */		{ $$.type = OT_None; }
+	| '=' int2			{ $$.type = OT_ParamValue; memcpy($$.value.intVectorValue, $2, sizeof($2)); }
+	;
+
+param_body_int3
+	: /* empty */		{ $$.type = OT_None; }
+	| '=' int3			{ $$.type = OT_ParamValue; memcpy($$.value.intVectorValue, $2, sizeof($2)); }
+	;
+
+param_body_int4
+	: /* empty */		{ $$.type = OT_None; }
+	| '=' int4			{ $$.type = OT_ParamValue; memcpy($$.value.intVectorValue, $2, sizeof($2)); }
+	;
+
+param_body_mat6
+	: /* empty */		{ $$.type = OT_None; }
+	| '=' mat6			{ $$.type = OT_ParamValue; memcpy($$.value.matrixValue, $2, sizeof($2)); }
+	;
+
+param_body_mat8
+	: /* empty */		{ $$.type = OT_None; }
+	| '=' mat8			{ $$.type = OT_ParamValue; memcpy($$.value.matrixValue, $2, sizeof($2)); }
+	;
+
+param_body_mat9
+	: /* empty */		{ $$.type = OT_None; }
+	| '=' mat9			{ $$.type = OT_ParamValue; memcpy($$.value.matrixValue, $2, sizeof($2)); }
+	;
+
+param_body_mat12
+	: /* empty */		{ $$.type = OT_None; }
+	| '=' mat12			{ $$.type = OT_ParamValue; memcpy($$.value.matrixValue, $2, sizeof($2)); }
+	;
+
+param_body_mat16
+	: /* empty */		{ $$.type = OT_None; }
+	| '=' mat16			{ $$.type = OT_ParamValue; memcpy($$.value.matrixValue, $2, sizeof($2)); }
+	;
+
+param_body_sampler
+	: /* empty */		{ $$.type = OT_None; }
+	| '=' '{' sampler_state_body '}' { }
+	;
+
+param_body_tex
+	: /* empty */		{ $$.type = OT_None; }
+	| '=' TOKEN_STRING	{ $$.type = OT_ParamStrValue; $$.value.strValue = $2; }
+	;
+
+	/* Blocks */
+blocks
+	: blocks_header '{' blocks_body '}' ';' { nodePop(parse_state); $$ = $1; }
+	;
+
+blocks_header
+	: TOKEN_BLOCKS '='
+		{ 
+			$$ = nodeCreate(parse_state->memContext, NT_Blocks); 
+			nodePush(parse_state, $$);
+		}
+	;
+
+blocks_body
+	: /* empty */
+	| block blocks_body		{ nodeOptionsAdd(parse_state->memContext, parse_state->topNode->options, &$1); }
+	;
+
+block
+	: block_header qualifier_list ';' { nodePop(parse_state); $$.type = OT_Block; $$.value.nodePtr = $1; }
+	;
+
+block_header
+	: TOKEN_PARAMSBLOCK TOKEN_IDENTIFIER
+		{
+			$$ = nodeCreate(parse_state->memContext, NT_Block);
+			nodePush(parse_state, $$);
+
+			NodeOption blockName;
+			blockName.type = OT_Identifier;
+			blockName.value.strValue = $2;
+
+			nodeOptionsAdd(parse_state->memContext, parse_state->topNode->options, &blockName);
+		}
+	;
+
+	/* Qualifiers */
+qualifier_list
+	: /* empty */
+	| qualifier qualifier_list		{ nodeOptionsAdd(parse_state->memContext, parse_state->topNode->options, &$1); }
+	;
+
+qualifier
+	: ':' TOKEN_ALIAS '(' TOKEN_STRING ')'		{ $$.type = OT_Alias; $$.value.strValue = $4; }
+	| ':' TOKEN_AUTO '(' TOKEN_STRING ')'		{ $$.type = OT_Auto; $$.value.strValue = $4; }
+	| ':' TOKEN_SHARED '(' TOKEN_BOOLEAN ')'	{ $$.type = OT_Shared; $$.value.intValue = $4; }
+	| ':' TOKEN_USAGE '(' TOKEN_BUFFERUSAGE ')'	{ $$.type = OT_Usage; $$.value.intValue = $4; }
+	;
+%%
+
+void yyerror(YYLTYPE *locp, ParseState* parse_state, yyscan_t scanner, const char *msg) 
+{ 
+	parse_state->hasError = 1;
+	parse_state->errorLine = locp->first_line;
+	parse_state->errorColumn = locp->first_column;
+	parse_state->errorMessage = mmalloc_strdup(parse_state->memContext, msg);
+	parse_state->errorFile = locp->filename;
 }
 }

+ 333 - 325
Source/BansheeSL/Include/BsASTFX.h

@@ -1,326 +1,334 @@
-//********************************** Banshee Engine (www.banshee3d.com) **************************************************//
-//**************** Copyright (c) 2016 Marko Pintera ([email protected]). All rights reserved. **********************//
-#ifndef __ASTFX_H__
-#define __ASTFX_H__
-
-#include <stdlib.h>
-#include <string.h>
-
-typedef enum tagNodeType NodeType;
-typedef enum tagOptionType OptionType;
-typedef enum tagOptionDataType OptionDataType;
-typedef enum tagParamType ParamType;
-typedef struct tagParseState ParseState;
-typedef struct tagOptionInfo OptionInfo;
-typedef union tagOptionData OptionData;
-typedef struct tagNodeOptions NodeOptions;
-typedef struct tagNodeOption NodeOption;
-typedef struct tagASTFXNode ASTFXNode;
-typedef struct tagNodeLink NodeLink;
-typedef struct tagIncludeData IncludeData;
-typedef struct tagIncludeLink IncludeLink;
-typedef struct tagConditionalData ConditionalData;
-typedef struct tagCodeString CodeString;
-typedef enum tagFillModeValue FillModeValue;
-typedef enum tagCullModeValue CullModeValue;
-typedef enum tagCompFuncValue CompFuncValue;
-typedef enum tagOpValue OpValue;
-typedef enum tagBlendOpValue BlendOpValue;
-typedef enum tagAddrModeValue AddrModeValue;
-typedef enum tagFilterValue FilterValue;
-typedef enum tagBufferUsageValue BufferUsageValue;
-
-enum tagNodeType
-{
-	NT_Shader,
-	NT_Technique,
-	NT_Parameters,
-	NT_Blocks,
-	NT_Pass,
-	NT_StencilOp,
-	NT_Target,
-	NT_BlendDef,
-	NT_SamplerState,
-	NT_AddrMode,
-	NT_Parameter,
-	NT_Block,
-	NT_CodeVertex,
-	NT_CodeFragment,
-	NT_CodeGeometry,
-	NT_CodeHull,
-	NT_CodeDomain,
-	NT_CodeCompute,
-	NT_CodeCommon,
-};
-
-enum tagOptionType
-{
-	OT_None = 0,
-	OT_Separable,
-	OT_Priority,
-	OT_Queue,
-	OT_Transparent,
-	OT_Technique,
-	OT_Renderer,
-	OT_Language,
-	OT_Pass,
-	OT_FillMode,
-	OT_CullMode,
-	OT_DepthBias,
-	OT_SDepthBias,
-	OT_DepthClip,
-	OT_Scissor,
-	OT_Multisample,
-	OT_AALine,
-	OT_DepthRead,
-	OT_DepthWrite,
-	OT_CompareFunc,
-	OT_Stencil,
-	OT_StencilReadMask,
-	OT_StencilWriteMask,
-	OT_StencilOpFront,
-	OT_StencilOpBack,
-	OT_PassOp,
-	OT_Fail,
-	OT_ZFail,
-	OT_AlphaToCoverage,
-	OT_IndependantBlend,
-	OT_Target,
-	OT_Index,
-	OT_Blend,
-	OT_Color,
-	OT_Alpha,
-	OT_WriteMask,
-	OT_Source,
-	OT_Dest,
-	OT_Op,
-	OT_AddrMode,
-	OT_MinFilter,
-	OT_MagFilter,
-	OT_MipFilter,
-	OT_MaxAniso,
-	OT_MipBias,
-	OT_MipMin,
-	OT_MipMax,
-	OT_BorderColor,
-	OT_U,
-	OT_V,
-	OT_W,
-	OT_Alias,
-	OT_Auto,
-	OT_Shared,
-	OT_Usage,
-	OT_ParamType,
-	OT_Identifier,
-	OT_ParamValue,
-	OT_ParamStrValue,
-	OT_Parameters,
-	OT_Blocks,
-	OT_Parameter,
-	OT_Block,
-	OT_SamplerState,
-	OT_Code,
-	OT_StencilRef
-};
-
-enum tagOptionDataType
-{
-	ODT_Int,
-	ODT_Float,
-	ODT_Bool,
-	ODT_String,
-	ODT_Complex,
-	ODT_Matrix
-};
-
-enum tagParamType
-{
-	PT_Float, PT_Float2, PT_Float3, PT_Float4, 
-	PT_Int, PT_Int2, PT_Int3, PT_Int4, PT_Color,
-	PT_Mat2x2, PT_Mat2x3, PT_Mat2x4,
-	PT_Mat3x2, PT_Mat3x3, PT_Mat3x4,
-	PT_Mat4x2, PT_Mat4x3, PT_Mat4x4,
-	PT_Sampler1D, PT_Sampler2D, PT_Sampler3D, PT_SamplerCUBE, PT_Sampler2DMS,
-	PT_Texture1D, PT_Texture2D, PT_Texture3D, PT_TextureCUBE, PT_Texture2DMS,
-	PT_ByteBuffer, PT_StructBuffer, PT_ByteBufferRW, PT_StructBufferRW,
-	PT_TypedBufferRW, PT_AppendBuffer, PT_ConsumeBuffer,
-	PT_Count // Keep at end
-};
-
-enum tagFillModeValue 
-{ 
-	FMV_Wire, FMV_Solid 
-};
-
-enum tagCullModeValue 
-{ 
-	CMV_None, CMV_CW, CMV_CCW 
-};
-
-enum tagCompFuncValue
-{ 
-	CFV_Fail, CFV_Pass, CFV_LT, CFV_LTE, 
-	CFV_EQ, CFV_NEQ, CFV_GTE, CFV_GT
-};
-
-enum tagOpValue 
-{ 
-	OV_Keep, OV_Zero, OV_Replace, OV_Incr, OV_Decr, 
-	OV_IncrWrap, OV_DecrWrap, OV_Invert, OV_One, OV_DestColor, 
-	OV_SrcColor, OV_InvDestColor, OV_InvSrcColor, OV_DestAlpha, 
-	OV_SrcAlpha, OV_InvDestAlpha, OV_InvSrcAlpha
-};
-
-enum tagBlendOpValue 
-{ 
-	BOV_Add, BOV_Subtract, BOV_RevSubtract, 
-	BOV_Min, BOV_Max 
-};
-
-enum tagAddrModeValue
-{
-	AMV_Wrap, AMV_Mirror, AMV_Clamp, AMV_Border
-};
-
-enum tagFilterValue 
-{ 
-	FV_None, FV_Point, FV_Linear, FV_Anisotropic, 
-	FV_PointCmp, FV_LinearCmp, FV_AnisotropicCmp 
-};
-
-enum tagBufferUsageValue 
-{ 
-	BUV_Static, BUV_Dynamic 
-};
-
-struct tagNodeLink
-{
-	ASTFXNode* node;
-	NodeLink* next;
-};
-
-struct tagIncludeData
-{
-	char* filename;
-	char* buffer;
-};
-
-struct tagIncludeLink
-{
-	IncludeData* data;
-	IncludeLink* next;
-};
-
-struct tagConditionalData
-{
-	int selfEnabled;
-	int enabled;
-
-	ConditionalData* next;
-};
-
-struct tagCodeString
-{
-	char* code;
-	int index;
-	int size;
-	int capacity;
-
-	CodeString* next;
-};
-
-struct tagParseState
-{
-	ASTFXNode* rootNode;
-	ASTFXNode* topNode;
-	void* memContext;
-
-	int hasError;
-	int errorLine;
-	int errorColumn;
-	const char* errorMessage;
-	char* errorFile;
-
-	NodeLink* nodeStack;
-	IncludeLink* includeStack;
-	IncludeLink* includes;
-	CodeString* codeStrings;
-	int numCodeStrings;
-	int numOpenBrackets;
-
-	char** defines;
-	int numDefines;
-	int defineCapacity;
-	ConditionalData* conditionalStack;
-};
-
-struct tagOptionInfo
-{
-	OptionType type;
-	OptionDataType dataType;
-};
-
-union tagOptionData
-{
-	int intValue;
-	float floatValue;
-	const char* strValue;
-	float matrixValue[16];
-	int intVectorValue[4];
-	ASTFXNode* nodePtr;
-};
-
-struct tagNodeOption
-{
-	OptionType type;
-	OptionData value;
-};
-
-struct tagNodeOptions
-{
-	NodeOption* entries;
-
-	int count;
-	int bufferSize;
-};
-
-struct tagASTFXNode
-{
-	NodeType type;
-	NodeOptions* options;
-};
-
-OptionInfo OPTION_LOOKUP[];
-
-NodeOptions* nodeOptionsCreate(void* context);
-void nodeOptionDelete(NodeOption* option);
-void nodeOptionsDelete(NodeOptions* options);
-void nodeOptionsResize(void* context, NodeOptions* options, int size);
-void nodeOptionsGrowIfNeeded(void* context, NodeOptions* options);
-void nodeOptionsAdd(void* context, NodeOptions* options, const NodeOption* option);
-
-ASTFXNode* nodeCreate(void* context, NodeType type);
-void nodeDelete(ASTFXNode* node);
-
-void nodePush(ParseState* parseState, ASTFXNode* node);
-void nodePop(ParseState* parseState);
-
-void beginCodeBlock(ParseState* parseState);
-void appendCodeBlock(ParseState* parseState, const char* value, int size);
-int getCodeBlockIndex(ParseState* parseState);
-
-void addDefine(ParseState* parseState, const char* value);
-int hasDefine(ParseState* parseState, const char* value);
-void removeDefine(ParseState* parseState, const char* value);
-
-int pushConditional(ParseState* parseState, int state);
-int switchConditional(ParseState* parseState);
-int setConditional(ParseState* parseState, int state);
-int popConditional(ParseState* parseState);
-
-char* getCurrentFilename(ParseState* parseState);
-
-ParseState* parseStateCreate();
-void parseStateDelete(ParseState* parseState);
-
+//********************************** Banshee Engine (www.banshee3d.com) **************************************************//
+//**************** Copyright (c) 2016 Marko Pintera ([email protected]). All rights reserved. **********************//
+#ifndef __ASTFX_H__
+#define __ASTFX_H__
+
+#include <stdlib.h>
+#include <string.h>
+
+typedef enum tagNodeType NodeType;
+typedef enum tagOptionType OptionType;
+typedef enum tagOptionDataType OptionDataType;
+typedef enum tagParamType ParamType;
+typedef struct tagParseState ParseState;
+typedef struct tagOptionInfo OptionInfo;
+typedef union tagOptionData OptionData;
+typedef struct tagNodeOptions NodeOptions;
+typedef struct tagNodeOption NodeOption;
+typedef struct tagASTFXNode ASTFXNode;
+typedef struct tagNodeLink NodeLink;
+typedef struct tagIncludeData IncludeData;
+typedef struct tagIncludeLink IncludeLink;
+typedef struct tagConditionalData ConditionalData;
+typedef struct tagCodeString CodeString;
+typedef struct tagDefineEntry DefineEntry;
+typedef enum tagFillModeValue FillModeValue;
+typedef enum tagCullModeValue CullModeValue;
+typedef enum tagCompFuncValue CompFuncValue;
+typedef enum tagOpValue OpValue;
+typedef enum tagBlendOpValue BlendOpValue;
+typedef enum tagAddrModeValue AddrModeValue;
+typedef enum tagFilterValue FilterValue;
+typedef enum tagBufferUsageValue BufferUsageValue;
+
+enum tagNodeType
+{
+	NT_Shader,
+	NT_Technique,
+	NT_Parameters,
+	NT_Blocks,
+	NT_Pass,
+	NT_StencilOp,
+	NT_Target,
+	NT_BlendDef,
+	NT_SamplerState,
+	NT_AddrMode,
+	NT_Parameter,
+	NT_Block,
+	NT_CodeVertex,
+	NT_CodeFragment,
+	NT_CodeGeometry,
+	NT_CodeHull,
+	NT_CodeDomain,
+	NT_CodeCompute,
+	NT_CodeCommon,
+};
+
+enum tagOptionType
+{
+	OT_None = 0,
+	OT_Separable,
+	OT_Priority,
+	OT_Queue,
+	OT_Transparent,
+	OT_Technique,
+	OT_Renderer,
+	OT_Language,
+	OT_Pass,
+	OT_FillMode,
+	OT_CullMode,
+	OT_DepthBias,
+	OT_SDepthBias,
+	OT_DepthClip,
+	OT_Scissor,
+	OT_Multisample,
+	OT_AALine,
+	OT_DepthRead,
+	OT_DepthWrite,
+	OT_CompareFunc,
+	OT_Stencil,
+	OT_StencilReadMask,
+	OT_StencilWriteMask,
+	OT_StencilOpFront,
+	OT_StencilOpBack,
+	OT_PassOp,
+	OT_Fail,
+	OT_ZFail,
+	OT_AlphaToCoverage,
+	OT_IndependantBlend,
+	OT_Target,
+	OT_Index,
+	OT_Blend,
+	OT_Color,
+	OT_Alpha,
+	OT_WriteMask,
+	OT_Source,
+	OT_Dest,
+	OT_Op,
+	OT_AddrMode,
+	OT_MinFilter,
+	OT_MagFilter,
+	OT_MipFilter,
+	OT_MaxAniso,
+	OT_MipBias,
+	OT_MipMin,
+	OT_MipMax,
+	OT_BorderColor,
+	OT_U,
+	OT_V,
+	OT_W,
+	OT_Alias,
+	OT_Auto,
+	OT_Shared,
+	OT_Usage,
+	OT_ParamType,
+	OT_Identifier,
+	OT_ParamValue,
+	OT_ParamStrValue,
+	OT_Parameters,
+	OT_Blocks,
+	OT_Parameter,
+	OT_Block,
+	OT_SamplerState,
+	OT_Code,
+	OT_StencilRef
+};
+
+enum tagOptionDataType
+{
+	ODT_Int,
+	ODT_Float,
+	ODT_Bool,
+	ODT_String,
+	ODT_Complex,
+	ODT_Matrix
+};
+
+enum tagParamType
+{
+	PT_Float, PT_Float2, PT_Float3, PT_Float4, 
+	PT_Int, PT_Int2, PT_Int3, PT_Int4, PT_Color,
+	PT_Mat2x2, PT_Mat2x3, PT_Mat2x4,
+	PT_Mat3x2, PT_Mat3x3, PT_Mat3x4,
+	PT_Mat4x2, PT_Mat4x3, PT_Mat4x4,
+	PT_Sampler1D, PT_Sampler2D, PT_Sampler3D, PT_SamplerCUBE, PT_Sampler2DMS,
+	PT_Texture1D, PT_Texture2D, PT_Texture3D, PT_TextureCUBE, PT_Texture2DMS,
+	PT_ByteBuffer, PT_StructBuffer, PT_ByteBufferRW, PT_StructBufferRW,
+	PT_TypedBufferRW, PT_AppendBuffer, PT_ConsumeBuffer,
+	PT_Count // Keep at end
+};
+
+enum tagFillModeValue 
+{ 
+	FMV_Wire, FMV_Solid 
+};
+
+enum tagCullModeValue 
+{ 
+	CMV_None, CMV_CW, CMV_CCW 
+};
+
+enum tagCompFuncValue
+{ 
+	CFV_Fail, CFV_Pass, CFV_LT, CFV_LTE, 
+	CFV_EQ, CFV_NEQ, CFV_GTE, CFV_GT
+};
+
+enum tagOpValue 
+{ 
+	OV_Keep, OV_Zero, OV_Replace, OV_Incr, OV_Decr, 
+	OV_IncrWrap, OV_DecrWrap, OV_Invert, OV_One, OV_DestColor, 
+	OV_SrcColor, OV_InvDestColor, OV_InvSrcColor, OV_DestAlpha, 
+	OV_SrcAlpha, OV_InvDestAlpha, OV_InvSrcAlpha
+};
+
+enum tagBlendOpValue 
+{ 
+	BOV_Add, BOV_Subtract, BOV_RevSubtract, 
+	BOV_Min, BOV_Max 
+};
+
+enum tagAddrModeValue
+{
+	AMV_Wrap, AMV_Mirror, AMV_Clamp, AMV_Border
+};
+
+enum tagFilterValue 
+{ 
+	FV_None, FV_Point, FV_Linear, FV_Anisotropic, 
+	FV_PointCmp, FV_LinearCmp, FV_AnisotropicCmp 
+};
+
+enum tagBufferUsageValue 
+{ 
+	BUV_Static, BUV_Dynamic 
+};
+
+struct tagNodeLink
+{
+	ASTFXNode* node;
+	NodeLink* next;
+};
+
+struct tagIncludeData
+{
+	char* filename;
+	char* buffer;
+};
+
+struct tagIncludeLink
+{
+	IncludeData* data;
+	IncludeLink* next;
+};
+
+struct tagConditionalData
+{
+	int selfEnabled;
+	int enabled;
+
+	ConditionalData* next;
+};
+
+struct tagCodeString
+{
+	char* code;
+	int index;
+	int size;
+	int capacity;
+
+	CodeString* next;
+};
+
+struct tagDefineEntry
+{
+	char* name;
+	char* expr;
+};
+
+struct tagParseState
+{
+	ASTFXNode* rootNode;
+	ASTFXNode* topNode;
+	void* memContext;
+
+	int hasError;
+	int errorLine;
+	int errorColumn;
+	const char* errorMessage;
+	char* errorFile;
+
+	NodeLink* nodeStack;
+	IncludeLink* includeStack;
+	IncludeLink* includes;
+	CodeString* codeStrings;
+	int numCodeStrings;
+	int numOpenBrackets;
+
+	DefineEntry* defines;
+	int numDefines;
+	int defineCapacity;
+	ConditionalData* conditionalStack;
+};
+
+struct tagOptionInfo
+{
+	OptionType type;
+	OptionDataType dataType;
+};
+
+union tagOptionData
+{
+	int intValue;
+	float floatValue;
+	const char* strValue;
+	float matrixValue[16];
+	int intVectorValue[4];
+	ASTFXNode* nodePtr;
+};
+
+struct tagNodeOption
+{
+	OptionType type;
+	OptionData value;
+};
+
+struct tagNodeOptions
+{
+	NodeOption* entries;
+
+	int count;
+	int bufferSize;
+};
+
+struct tagASTFXNode
+{
+	NodeType type;
+	NodeOptions* options;
+};
+
+OptionInfo OPTION_LOOKUP[];
+
+NodeOptions* nodeOptionsCreate(void* context);
+void nodeOptionDelete(NodeOption* option);
+void nodeOptionsDelete(NodeOptions* options);
+void nodeOptionsResize(void* context, NodeOptions* options, int size);
+void nodeOptionsGrowIfNeeded(void* context, NodeOptions* options);
+void nodeOptionsAdd(void* context, NodeOptions* options, const NodeOption* option);
+
+ASTFXNode* nodeCreate(void* context, NodeType type);
+void nodeDelete(ASTFXNode* node);
+
+void nodePush(ParseState* parseState, ASTFXNode* node);
+void nodePop(ParseState* parseState);
+
+void beginCodeBlock(ParseState* parseState);
+void appendCodeBlock(ParseState* parseState, const char* value, int size);
+int getCodeBlockIndex(ParseState* parseState);
+
+void addDefine(ParseState* parseState, const char* value);
+void addDefineExpr(ParseState* parseState, const char* value);
+int hasDefine(ParseState* parseState, const char* value);
+void removeDefine(ParseState* parseState, const char* value);
+
+int pushConditional(ParseState* parseState, int state);
+int switchConditional(ParseState* parseState);
+int setConditional(ParseState* parseState, int state);
+int popConditional(ParseState* parseState);
+
+char* getCurrentFilename(ParseState* parseState);
+
+ParseState* parseStateCreate();
+void parseStateDelete(ParseState* parseState);
+
 #endif
 #endif

+ 8 - 7
Source/BansheeSL/Include/BsLexerFX.h

@@ -227,11 +227,12 @@ void yyfree (void * ,yyscan_t yyscanner );
 #define CODEBLOCK 4
 #define CODEBLOCK 4
 #define CODEBLOCK_END 5
 #define CODEBLOCK_END 5
 #define DEFINE_COND 6
 #define DEFINE_COND 6
-#define UNDEF_COND 7
-#define CONDITIONAL_IF 8
-#define CONDITIONAL_IFN 9
-#define CONDITIONAL_ELIF 10
-#define CONDITIONAL_IGNORE 11
+#define DEFINE_COND_EXPR 7
+#define UNDEF_COND 8
+#define CONDITIONAL_IF 9
+#define CONDITIONAL_IFN 10
+#define CONDITIONAL_ELIF 11
+#define CONDITIONAL_IGNORE 12
 
 
 #endif
 #endif
 
 
@@ -348,9 +349,9 @@ extern int yylex \
 #undef YY_DECL
 #undef YY_DECL
 #endif
 #endif
 
 
-#line 378 "..\\..\\Source\\BansheeSL\\BsLexerFX.l"
+#line 386 "..\\..\\Source\\BansheeSL\\BsLexerFX.l"
 
 
 
 
-#line 355 "BsLexerFX.h"
+#line 356 "BsLexerFX.h"
 #undef yyIN_HEADER
 #undef yyIN_HEADER
 #endif /* yyHEADER_H */
 #endif /* yyHEADER_H */

+ 2 - 2
Source/BansheeSL/Include/BsParserFX.h

@@ -34,7 +34,7 @@
 # define YY_YY_BSPARSERFX_H_INCLUDED
 # define YY_YY_BSPARSERFX_H_INCLUDED
 /* Enabling traces.  */
 /* Enabling traces.  */
 #ifndef YYDEBUG
 #ifndef YYDEBUG
-# define YYDEBUG 0
+# define YYDEBUG 1
 #endif
 #endif
 #if YYDEBUG
 #if YYDEBUG
 extern int yydebug;
 extern int yydebug;
@@ -225,7 +225,7 @@ typedef struct YYLTYPE {
 typedef union YYSTYPE
 typedef union YYSTYPE
 {
 {
 /* Line 2579 of glr.c  */
 /* Line 2579 of glr.c  */
-#line 73 "..\\..\\Source\\BansheeSL\\BsParserFX.y"
+#line 74 "..\\..\\Source\\BansheeSL\\BsParserFX.y"
 
 
 	int intValue;
 	int intValue;
 	float floatValue;
 	float floatValue;

+ 1 - 1
Source/BansheeSL/Include/BsSLFXCompiler.h

@@ -73,7 +73,7 @@ namespace BansheeEngine
 
 
 	public:
 	public:
 		/**	Transforms a source file written in BSL FX syntax into a Shader object. */
 		/**	Transforms a source file written in BSL FX syntax into a Shader object. */
-		static BSLFXCompileResult compile(const String& source);
+		static BSLFXCompileResult compile(const String& source, const UnorderedMap<String, String>& defines);
 
 
 	private:
 	private:
 		/** Converts the provided source into an abstract syntax tree using the lexer & parser for BSL FX syntax. */
 		/** Converts the provided source into an abstract syntax tree using the lexer & parser for BSL FX syntax. */

+ 412 - 392
Source/BansheeSL/Source/BsASTFX.c

@@ -1,393 +1,413 @@
-//********************************** Banshee Engine (www.banshee3d.com) **************************************************//
-//**************** Copyright (c) 2016 Marko Pintera ([email protected]). All rights reserved. **********************//
-#include "BsASTFX.h"
-#include "BsMMAlloc.h"
-
-OptionInfo OPTION_LOOKUP[] =
-{
-	{ OT_None, ODT_Int },
-	{ OT_Separable, ODT_Bool },
-	{ OT_Priority, ODT_Int },
-	{ OT_Queue, ODT_Int },
-	{ OT_Transparent, ODT_Bool },
-	{ OT_Technique, ODT_Complex }, 
-	{ OT_Renderer, ODT_String }, 
-	{ OT_Language, ODT_String }, 
-	{ OT_Pass, ODT_Complex }, 
-	{ OT_FillMode, ODT_Int }, 
-	{ OT_CullMode, ODT_Int },
-	{ OT_DepthBias, ODT_Float },
-	{ OT_SDepthBias, ODT_Float },
-	{ OT_DepthClip, ODT_Bool },
-	{ OT_Scissor, ODT_Bool },
-	{ OT_Multisample, ODT_Bool },
-	{ OT_AALine, ODT_Bool },
-	{ OT_DepthRead, ODT_Bool },
-	{ OT_DepthWrite, ODT_Bool },
-	{ OT_CompareFunc, ODT_Int },
-	{ OT_Stencil, ODT_Bool },
-	{ OT_StencilReadMask, ODT_Int },
-	{ OT_StencilWriteMask, ODT_Int },
-	{ OT_StencilOpFront, ODT_Complex },
-	{ OT_StencilOpBack, ODT_Complex },
-	{ OT_PassOp, ODT_Int },
-	{ OT_Fail, ODT_Int },
-	{ OT_ZFail, ODT_Int },
-	{ OT_AlphaToCoverage, ODT_Bool },
-	{ OT_IndependantBlend, ODT_Bool },
-	{ OT_Target, ODT_Complex },
-	{ OT_Index, ODT_Int },
-	{ OT_Blend, ODT_Bool },
-	{ OT_Color, ODT_Complex },
-	{ OT_Alpha, ODT_Complex },
-	{ OT_WriteMask, ODT_Int },
-	{ OT_Source, ODT_Int },
-	{ OT_Dest, ODT_Int },
-	{ OT_Op, ODT_Int },
-	{ OT_AddrMode, ODT_Complex },
-	{ OT_MinFilter, ODT_Int },
-	{ OT_MagFilter, ODT_Int },
-	{ OT_MipFilter, ODT_Int },
-	{ OT_MaxAniso, ODT_Int },
-	{ OT_MipBias, ODT_Float },
-	{ OT_MipMin, ODT_Float },
-	{ OT_MipMax, ODT_Float },
-	{ OT_BorderColor, ODT_Matrix },
-	{ OT_U, ODT_Int },
-	{ OT_V, ODT_Int },
-	{ OT_W, ODT_Int },
-	{ OT_Alias, ODT_String },
-	{ OT_Auto, ODT_String },
-	{ OT_Shared, ODT_Bool },
-	{ OT_Usage, ODT_Int },
-	{ OT_ParamType, ODT_Int },
-	{ OT_Identifier, ODT_String },
-	{ OT_ParamValue, ODT_Matrix },
-	{ OT_ParamStrValue, ODT_String },
-	{ OT_Parameters, ODT_Complex },
-	{ OT_Blocks, ODT_Complex },
-	{ OT_Parameter, ODT_Complex },
-	{ OT_Block, ODT_Complex },
-	{ OT_SamplerState, ODT_Complex },
-	{ OT_Code, ODT_Complex },
-	{ OT_StencilRef, ODT_Int }
-};
-
-NodeOptions* nodeOptionsCreate(void* context)
-{
-	static const int BUFFER_SIZE = 5;
-
-	NodeOptions* options = (NodeOptions*)mmalloc(context, sizeof(NodeOptions));
-	options->count = 0;
-	options->bufferSize = BUFFER_SIZE;
-
-	options->entries = (NodeOption*)mmalloc(context, sizeof(NodeOption) * options->bufferSize);
-	memset(options->entries, 0, sizeof(NodeOption) * options->bufferSize);
-
-	return options;
-}
-
-void nodeOptionDelete(NodeOption* option)
-{
-	if (OPTION_LOOKUP[(int)option->type].dataType == ODT_Complex)
-	{
-		nodeDelete(option->value.nodePtr);
-		option->value.nodePtr = 0;
-	}
-	else if (OPTION_LOOKUP[(int)option->type].dataType == ODT_String)
-	{
-		mmfree((void*)option->value.strValue);
-		option->value.strValue = 0;
-	}
-}
-
-void nodeOptionsDelete(NodeOptions* options)
-{
-	int i = 0;
-
-	for (i = 0; i < options->count; i++)
-		nodeOptionDelete(&options->entries[i]);
-
-	mmfree(options->entries);
-	mmfree(options);
-}
-
-void nodeOptionsResize(void* context, NodeOptions* options, int size)
-{
-	NodeOption* originalEntries = options->entries;
-	int originalSize = options->bufferSize;
-	int originalCount = options->count;
-	int i = 0;
-	int elementsToCopy = originalSize;
-	int sizeToCopy = 0;
-
-	options->bufferSize = size;
-	if (options->count > options->bufferSize)
-		options->count = options->bufferSize;
-
-	if (elementsToCopy > size)
-		elementsToCopy = size;
-
-	sizeToCopy = elementsToCopy * sizeof(NodeOption);
-
-	options->entries = (NodeOption*)mmalloc(context, sizeof(NodeOption) * options->bufferSize);
-
-	memcpy(options->entries, originalEntries, sizeToCopy);
-	memset(options->entries + elementsToCopy, 0, sizeof(NodeOption) * options->bufferSize - sizeToCopy);
-
-	mmfree(originalEntries);
-}
-
-void nodeOptionsGrowIfNeeded(void* context, NodeOptions* options)
-{
-	static const int BUFFER_GROW = 10;
-
-	if (options->count == options->bufferSize)
-		nodeOptionsResize(context, options, options->bufferSize + BUFFER_GROW);
-}
-
-void nodeOptionsAdd(void* context, NodeOptions* options, const NodeOption* option)
-{
-	nodeOptionsGrowIfNeeded(context, options);
-
-	options->entries[options->count] = *option;
-	options->count++;
-}
-
-ASTFXNode* nodeCreate(void* context, NodeType type)
-{
-	ASTFXNode* node = (ASTFXNode*)mmalloc(context, sizeof(ASTFXNode));
-	node->options = nodeOptionsCreate(context);
-	node->type = type;
-
-	return node;
-}
-
-void nodeDelete(ASTFXNode* node)
-{
-	nodeOptionsDelete(node->options);
-
-	mmfree(node);
-}
-
-void nodePush(ParseState* parseState, ASTFXNode* node)
-{
-	NodeLink* linkNode = (NodeLink*)mmalloc(parseState->memContext, sizeof(NodeLink));
-	linkNode->next = parseState->nodeStack;
-	linkNode->node = node;
-
-	parseState->nodeStack = linkNode;
-	parseState->topNode = node;
-}
-
-void nodePop(ParseState* parseState)
-{
-	if (!parseState->nodeStack)
-		return;
-
-	NodeLink* toRemove = parseState->nodeStack;
-	parseState->nodeStack = toRemove->next;
-
-	if (parseState->nodeStack)
-		parseState->topNode = parseState->nodeStack->node;
-	else
-		parseState->topNode = 0;
-
-	mmfree(toRemove);
-}
-
-void beginCodeBlock(ParseState* parseState)
-{
-	CodeString* codeString = (CodeString*)mmalloc(parseState->memContext, sizeof(CodeString));
-	codeString->index = parseState->numCodeStrings;
-	codeString->size = 0;
-	codeString->capacity = 4096;
-	codeString->code = mmalloc(parseState->memContext, codeString->capacity);
-	codeString->next = parseState->codeStrings;
-
-	parseState->numCodeStrings++;
-	parseState->codeStrings = codeString;
-
-	// Insert defines for code-blocks as we don't perform pre-processing within code blocks but we still want outer defines
-	// to be recognized by them (Performing pre-processing for code blocks is problematic because it would require parsing
-	// of all the language syntax in order to properly handle macro replacement).
-	for (int i = 0; i < parseState->numDefines; i++)
-	{
-		const char* define = "#define ";
-
-		appendCodeBlock(parseState, define, (int)strlen(define));
-		appendCodeBlock(parseState, parseState->defines[i], (int)strlen(parseState->defines[i]));
-	}
-}
-
-void appendCodeBlock(ParseState* parseState, const char* value, int size)
-{
-	CodeString* codeString = parseState->codeStrings;
-
-	if ((codeString->size + size) > codeString->capacity)
-	{
-		int newCapacity = codeString->capacity;
-		do 
-		{
-			newCapacity *= 2;
-		} while ((codeString->size + size) > newCapacity);
-
-		char* newBuffer = mmalloc(parseState->memContext, newCapacity);
-		memcpy(newBuffer, codeString->code, codeString->size);
-		mmfree(codeString->code);
-
-		codeString->code = newBuffer;
-		codeString->capacity = newCapacity;
-	}
-
-	memcpy(&codeString->code[codeString->size], value, size);
-	codeString->size += size;
-}
-
-int getCodeBlockIndex(ParseState* parseState)
-{
-	return parseState->codeStrings->index;
-}
-
-char* getCurrentFilename(ParseState* parseState)
-{
-	if (!parseState->includeStack)
-		return NULL;
-
-	return parseState->includeStack->data->filename;
-}
-
-void addDefine(ParseState* parseState, const char* value)
-{
-	int defineIdx = parseState->numDefines;
-	parseState->numDefines++;
-
-	if(parseState->numDefines > parseState->defineCapacity)
-	{
-		int newCapacity = parseState->defineCapacity * 2;
-		char** newDefines = mmalloc(parseState->memContext, newCapacity * sizeof(char*));
-
-		memcpy(newDefines, parseState->defines, parseState->defineCapacity);
-
-		mmfree(parseState->defines);
-		parseState->defines = newDefines;
-		parseState->defineCapacity = newCapacity;
-	}
-
-	parseState->defines[defineIdx] = mmalloc_strdup(parseState->memContext, value);
-}
-
-int hasDefine(ParseState* parseState, const char* value)
-{
-	for (int i = 0; i < parseState->numDefines; i++)
-	{
-		if (strcmp(parseState->defines[i], value) == 0)
-			return 1;
-	}
-
-	return 0;
-}
-
-void removeDefine(ParseState* parseState, const char* value)
-{
-	for (int i = 0; i < parseState->numDefines; i++)
-	{
-		if (strcmp(parseState->defines[i], value) == 0)
-		{
-			int remaining = parseState->numDefines - (i + 1);
-
-			if(remaining > 0)
-				memcpy(&parseState->defines[i], &parseState->defines[i + 1], remaining);
-
-			parseState->numDefines--;
-		}
-	}
-}
-
-int pushConditional(ParseState* parseState, int state)
-{
-	ConditionalData* conditional = mmalloc(parseState->memContext, sizeof(ConditionalData));
-	conditional->enabled = state && (parseState->conditionalStack == 0 || parseState->conditionalStack->enabled);
-	conditional->selfEnabled = state;
-	conditional->next = parseState->conditionalStack;
-
-	parseState->conditionalStack = conditional;
-
-	return conditional->enabled;
-}
-
-int switchConditional(ParseState* parseState)
-{
-	if (parseState->conditionalStack == 0)
-		return 1;
-
-	ConditionalData* conditional = parseState->conditionalStack;
-	return setConditional(parseState, !conditional->selfEnabled);
-}
-
-int setConditional(ParseState* parseState, int state)
-{
-	if (parseState->conditionalStack == 0)
-		return 1;
-
-	ConditionalData* conditional = parseState->conditionalStack;
-	ConditionalData* parent = conditional->next;
-
-	conditional->enabled = state && (parent == 0 || parent->enabled);
-	conditional->selfEnabled = state;
-
-	return conditional->enabled;
-}
-
-int popConditional(ParseState* parseState)
-{
-	if (parseState->conditionalStack == 0)
-		return 1;
-
-	ConditionalData* conditional = parseState->conditionalStack;
-	parseState->conditionalStack = conditional->next;
-
-	mmfree(conditional);
-
-	return parseState->conditionalStack == 0 || parseState->conditionalStack->enabled;
-}
-
-ParseState* parseStateCreate()
-{
-	ParseState* parseState = (ParseState*)malloc(sizeof(ParseState));
-	parseState->memContext = mmalloc_new_context();
-	parseState->rootNode = nodeCreate(parseState->memContext, NT_Shader);
-	parseState->topNode = 0;
-	parseState->nodeStack = 0;
-	parseState->includeStack = 0;
-	parseState->includes = 0;
-	parseState->codeStrings = 0;
-	parseState->numCodeStrings = 0;
-	parseState->numOpenBrackets = 0;
-
-	parseState->hasError = 0;
-	parseState->errorLine = 0;
-	parseState->errorColumn = 0;
-	parseState->errorMessage = 0;
-	parseState->errorFile = 0;
-
-	parseState->conditionalStack = 0;
-	parseState->defineCapacity = 10;
-	parseState->numDefines = 0;
-	parseState->defines = mmalloc(parseState->memContext, parseState->defineCapacity * sizeof(char*));
-
-	nodePush(parseState, parseState->rootNode);
-
-	return parseState;
-}
-
-void parseStateDelete(ParseState* parseState)
-{
-	while (parseState->nodeStack != 0)
-		nodePop(parseState);
-
-	nodeDelete(parseState->rootNode);
-	mmalloc_free_context(parseState->memContext);
-
-	free(parseState);
+//********************************** Banshee Engine (www.banshee3d.com) **************************************************//
+//**************** Copyright (c) 2016 Marko Pintera ([email protected]). All rights reserved. **********************//
+#include "BsASTFX.h"
+#include "BsMMAlloc.h"
+#include <assert.h>
+
+OptionInfo OPTION_LOOKUP[] =
+{
+	{ OT_None, ODT_Int },
+	{ OT_Separable, ODT_Bool },
+	{ OT_Priority, ODT_Int },
+	{ OT_Queue, ODT_Int },
+	{ OT_Transparent, ODT_Bool },
+	{ OT_Technique, ODT_Complex }, 
+	{ OT_Renderer, ODT_String }, 
+	{ OT_Language, ODT_String }, 
+	{ OT_Pass, ODT_Complex }, 
+	{ OT_FillMode, ODT_Int }, 
+	{ OT_CullMode, ODT_Int },
+	{ OT_DepthBias, ODT_Float },
+	{ OT_SDepthBias, ODT_Float },
+	{ OT_DepthClip, ODT_Bool },
+	{ OT_Scissor, ODT_Bool },
+	{ OT_Multisample, ODT_Bool },
+	{ OT_AALine, ODT_Bool },
+	{ OT_DepthRead, ODT_Bool },
+	{ OT_DepthWrite, ODT_Bool },
+	{ OT_CompareFunc, ODT_Int },
+	{ OT_Stencil, ODT_Bool },
+	{ OT_StencilReadMask, ODT_Int },
+	{ OT_StencilWriteMask, ODT_Int },
+	{ OT_StencilOpFront, ODT_Complex },
+	{ OT_StencilOpBack, ODT_Complex },
+	{ OT_PassOp, ODT_Int },
+	{ OT_Fail, ODT_Int },
+	{ OT_ZFail, ODT_Int },
+	{ OT_AlphaToCoverage, ODT_Bool },
+	{ OT_IndependantBlend, ODT_Bool },
+	{ OT_Target, ODT_Complex },
+	{ OT_Index, ODT_Int },
+	{ OT_Blend, ODT_Bool },
+	{ OT_Color, ODT_Complex },
+	{ OT_Alpha, ODT_Complex },
+	{ OT_WriteMask, ODT_Int },
+	{ OT_Source, ODT_Int },
+	{ OT_Dest, ODT_Int },
+	{ OT_Op, ODT_Int },
+	{ OT_AddrMode, ODT_Complex },
+	{ OT_MinFilter, ODT_Int },
+	{ OT_MagFilter, ODT_Int },
+	{ OT_MipFilter, ODT_Int },
+	{ OT_MaxAniso, ODT_Int },
+	{ OT_MipBias, ODT_Float },
+	{ OT_MipMin, ODT_Float },
+	{ OT_MipMax, ODT_Float },
+	{ OT_BorderColor, ODT_Matrix },
+	{ OT_U, ODT_Int },
+	{ OT_V, ODT_Int },
+	{ OT_W, ODT_Int },
+	{ OT_Alias, ODT_String },
+	{ OT_Auto, ODT_String },
+	{ OT_Shared, ODT_Bool },
+	{ OT_Usage, ODT_Int },
+	{ OT_ParamType, ODT_Int },
+	{ OT_Identifier, ODT_String },
+	{ OT_ParamValue, ODT_Matrix },
+	{ OT_ParamStrValue, ODT_String },
+	{ OT_Parameters, ODT_Complex },
+	{ OT_Blocks, ODT_Complex },
+	{ OT_Parameter, ODT_Complex },
+	{ OT_Block, ODT_Complex },
+	{ OT_SamplerState, ODT_Complex },
+	{ OT_Code, ODT_Complex },
+	{ OT_StencilRef, ODT_Int }
+};
+
+NodeOptions* nodeOptionsCreate(void* context)
+{
+	static const int BUFFER_SIZE = 5;
+
+	NodeOptions* options = (NodeOptions*)mmalloc(context, sizeof(NodeOptions));
+	options->count = 0;
+	options->bufferSize = BUFFER_SIZE;
+
+	options->entries = (NodeOption*)mmalloc(context, sizeof(NodeOption) * options->bufferSize);
+	memset(options->entries, 0, sizeof(NodeOption) * options->bufferSize);
+
+	return options;
+}
+
+void nodeOptionDelete(NodeOption* option)
+{
+	if (OPTION_LOOKUP[(int)option->type].dataType == ODT_Complex)
+	{
+		nodeDelete(option->value.nodePtr);
+		option->value.nodePtr = 0;
+	}
+	else if (OPTION_LOOKUP[(int)option->type].dataType == ODT_String)
+	{
+		mmfree((void*)option->value.strValue);
+		option->value.strValue = 0;
+	}
+}
+
+void nodeOptionsDelete(NodeOptions* options)
+{
+	int i = 0;
+
+	for (i = 0; i < options->count; i++)
+		nodeOptionDelete(&options->entries[i]);
+
+	mmfree(options->entries);
+	mmfree(options);
+}
+
+void nodeOptionsResize(void* context, NodeOptions* options, int size)
+{
+	NodeOption* originalEntries = options->entries;
+	int originalSize = options->bufferSize;
+	int originalCount = options->count;
+	int i = 0;
+	int elementsToCopy = originalSize;
+	int sizeToCopy = 0;
+
+	options->bufferSize = size;
+	if (options->count > options->bufferSize)
+		options->count = options->bufferSize;
+
+	if (elementsToCopy > size)
+		elementsToCopy = size;
+
+	sizeToCopy = elementsToCopy * sizeof(NodeOption);
+
+	options->entries = (NodeOption*)mmalloc(context, sizeof(NodeOption) * options->bufferSize);
+
+	memcpy(options->entries, originalEntries, sizeToCopy);
+	memset(options->entries + elementsToCopy, 0, sizeof(NodeOption) * options->bufferSize - sizeToCopy);
+
+	mmfree(originalEntries);
+}
+
+void nodeOptionsGrowIfNeeded(void* context, NodeOptions* options)
+{
+	static const int BUFFER_GROW = 10;
+
+	if (options->count == options->bufferSize)
+		nodeOptionsResize(context, options, options->bufferSize + BUFFER_GROW);
+}
+
+void nodeOptionsAdd(void* context, NodeOptions* options, const NodeOption* option)
+{
+	nodeOptionsGrowIfNeeded(context, options);
+
+	options->entries[options->count] = *option;
+	options->count++;
+}
+
+ASTFXNode* nodeCreate(void* context, NodeType type)
+{
+	ASTFXNode* node = (ASTFXNode*)mmalloc(context, sizeof(ASTFXNode));
+	node->options = nodeOptionsCreate(context);
+	node->type = type;
+
+	return node;
+}
+
+void nodeDelete(ASTFXNode* node)
+{
+	nodeOptionsDelete(node->options);
+
+	mmfree(node);
+}
+
+void nodePush(ParseState* parseState, ASTFXNode* node)
+{
+	NodeLink* linkNode = (NodeLink*)mmalloc(parseState->memContext, sizeof(NodeLink));
+	linkNode->next = parseState->nodeStack;
+	linkNode->node = node;
+
+	parseState->nodeStack = linkNode;
+	parseState->topNode = node;
+}
+
+void nodePop(ParseState* parseState)
+{
+	if (!parseState->nodeStack)
+		return;
+
+	NodeLink* toRemove = parseState->nodeStack;
+	parseState->nodeStack = toRemove->next;
+
+	if (parseState->nodeStack)
+		parseState->topNode = parseState->nodeStack->node;
+	else
+		parseState->topNode = 0;
+
+	mmfree(toRemove);
+}
+
+void beginCodeBlock(ParseState* parseState)
+{
+	CodeString* codeString = (CodeString*)mmalloc(parseState->memContext, sizeof(CodeString));
+	codeString->index = parseState->numCodeStrings;
+	codeString->size = 0;
+	codeString->capacity = 4096;
+	codeString->code = mmalloc(parseState->memContext, codeString->capacity);
+	codeString->next = parseState->codeStrings;
+
+	parseState->numCodeStrings++;
+	parseState->codeStrings = codeString;
+
+	// Insert defines for code-blocks as we don't perform pre-processing within code blocks but we still want outer defines
+	// to be recognized by them (Performing pre-processing for code blocks is problematic because it would require parsing
+	// of all the language syntax in order to properly handle macro replacement).
+	for (int i = 0; i < parseState->numDefines; i++)
+	{
+		const char* define = "#define ";
+
+		appendCodeBlock(parseState, define, (int)strlen(define));
+		appendCodeBlock(parseState, parseState->defines[i].name, (int)strlen(parseState->defines[i].name));
+
+		if (parseState->defines[i].expr != 0)
+		{
+			appendCodeBlock(parseState, parseState->defines[i].expr, (int)strlen(parseState->defines[i].expr));
+			appendCodeBlock(parseState, "\n", 1);
+		}
+	}
+}
+
+void appendCodeBlock(ParseState* parseState, const char* value, int size)
+{
+	CodeString* codeString = parseState->codeStrings;
+
+	if ((codeString->size + size) > codeString->capacity)
+	{
+		int newCapacity = codeString->capacity;
+		do 
+		{
+			newCapacity *= 2;
+		} while ((codeString->size + size) > newCapacity);
+
+		char* newBuffer = mmalloc(parseState->memContext, newCapacity);
+		memcpy(newBuffer, codeString->code, codeString->size);
+		mmfree(codeString->code);
+
+		codeString->code = newBuffer;
+		codeString->capacity = newCapacity;
+	}
+
+	memcpy(&codeString->code[codeString->size], value, size);
+	codeString->size += size;
+}
+
+int getCodeBlockIndex(ParseState* parseState)
+{
+	return parseState->codeStrings->index;
+}
+
+char* getCurrentFilename(ParseState* parseState)
+{
+	if (!parseState->includeStack)
+		return NULL;
+
+	return parseState->includeStack->data->filename;
+}
+
+void addDefine(ParseState* parseState, const char* value)
+{
+	int defineIdx = parseState->numDefines;
+	parseState->numDefines++;
+
+	if(parseState->numDefines > parseState->defineCapacity)
+	{
+		int newCapacity = parseState->defineCapacity * 2;
+		DefineEntry* newDefines = mmalloc(parseState->memContext, newCapacity * sizeof(DefineEntry));
+
+		memcpy(newDefines, parseState->defines, parseState->defineCapacity * sizeof(DefineEntry));
+
+		mmfree(parseState->defines);
+		parseState->defines = newDefines;
+		parseState->defineCapacity = newCapacity;
+	}
+
+	parseState->defines[defineIdx].name = mmalloc_strdup(parseState->memContext, value);
+	parseState->defines[defineIdx].expr = 0;
+}
+
+void addDefineExpr(ParseState* parseState, const char* value)
+{
+	int defineIdx = parseState->numDefines - 1;
+	if(defineIdx < 0)
+	{
+		assert(0);
+		return;
+	}
+
+	parseState->defines[defineIdx].expr = mmalloc_strdup(parseState->memContext, value);
+}
+
+int hasDefine(ParseState* parseState, const char* value)
+{
+	for (int i = 0; i < parseState->numDefines; i++)
+	{
+		if (strcmp(parseState->defines[i].name, value) == 0)
+			return 1;
+	}
+
+	return 0;
+}
+
+void removeDefine(ParseState* parseState, const char* value)
+{
+	for (int i = 0; i < parseState->numDefines; i++)
+	{
+		if (strcmp(parseState->defines[i].name, value) == 0)
+		{
+			int remaining = parseState->numDefines - (i + 1);
+
+			if(remaining > 0)
+				memcpy(&parseState->defines[i], &parseState->defines[i + 1], remaining * sizeof(DefineEntry));
+
+			parseState->numDefines--;
+		}
+	}
+}
+
+int pushConditional(ParseState* parseState, int state)
+{
+	ConditionalData* conditional = mmalloc(parseState->memContext, sizeof(ConditionalData));
+	conditional->enabled = state && (parseState->conditionalStack == 0 || parseState->conditionalStack->enabled);
+	conditional->selfEnabled = state;
+	conditional->next = parseState->conditionalStack;
+
+	parseState->conditionalStack = conditional;
+
+	return conditional->enabled;
+}
+
+int switchConditional(ParseState* parseState)
+{
+	if (parseState->conditionalStack == 0)
+		return 1;
+
+	ConditionalData* conditional = parseState->conditionalStack;
+	return setConditional(parseState, !conditional->selfEnabled);
+}
+
+int setConditional(ParseState* parseState, int state)
+{
+	if (parseState->conditionalStack == 0)
+		return 1;
+
+	ConditionalData* conditional = parseState->conditionalStack;
+	ConditionalData* parent = conditional->next;
+
+	conditional->enabled = state && (parent == 0 || parent->enabled);
+	conditional->selfEnabled = state;
+
+	return conditional->enabled;
+}
+
+int popConditional(ParseState* parseState)
+{
+	if (parseState->conditionalStack == 0)
+		return 1;
+
+	ConditionalData* conditional = parseState->conditionalStack;
+	parseState->conditionalStack = conditional->next;
+
+	mmfree(conditional);
+
+	return parseState->conditionalStack == 0 || parseState->conditionalStack->enabled;
+}
+
+ParseState* parseStateCreate()
+{
+	ParseState* parseState = (ParseState*)malloc(sizeof(ParseState));
+	parseState->memContext = mmalloc_new_context();
+	parseState->rootNode = nodeCreate(parseState->memContext, NT_Shader);
+	parseState->topNode = 0;
+	parseState->nodeStack = 0;
+	parseState->includeStack = 0;
+	parseState->includes = 0;
+	parseState->codeStrings = 0;
+	parseState->numCodeStrings = 0;
+	parseState->numOpenBrackets = 0;
+
+	parseState->hasError = 0;
+	parseState->errorLine = 0;
+	parseState->errorColumn = 0;
+	parseState->errorMessage = 0;
+	parseState->errorFile = 0;
+
+	parseState->conditionalStack = 0;
+	parseState->defineCapacity = 10;
+	parseState->numDefines = 0;
+	parseState->defines = mmalloc(parseState->memContext, parseState->defineCapacity * sizeof(DefineEntry));
+
+	nodePush(parseState, parseState->rootNode);
+
+	return parseState;
+}
+
+void parseStateDelete(ParseState* parseState)
+{
+	while (parseState->nodeStack != 0)
+		nodePop(parseState);
+
+	nodeDelete(parseState->rootNode);
+	mmalloc_free_context(parseState->memContext);
+
+	free(parseState);
 }
 }

Fișier diff suprimat deoarece este prea mare
+ 593 - 570
Source/BansheeSL/Source/BsLexerFX.c


Fișier diff suprimat deoarece este prea mare
+ 153 - 153
Source/BansheeSL/Source/BsParserFX.c


+ 1363 - 1352
Source/BansheeSL/Source/BsSLFXCompiler.cpp

@@ -1,1353 +1,1364 @@
-//********************************** Banshee Engine (www.banshee3d.com) **************************************************//
-//**************** Copyright (c) 2016 Marko Pintera ([email protected]). All rights reserved. **********************//
-#include "BsSLFXCompiler.h"
-#include "BsGpuProgram.h"
-#include <regex>
-#include "BsShader.h"
-#include "BsTechnique.h"
-#include "BsPass.h"
-#include "BsSamplerState.h"
-#include "BsRenderAPI.h"
-#include "BsDebug.h"
-#include "BsShaderManager.h"
-#include "BsShaderInclude.h"
-#include "BsMatrix4.h"
-#include "BsBuiltinResources.h"
-
-extern "C" {
-#include "BsMMAlloc.h"
-#include "BsParserFX.h"
-#include "BsLexerFX.h"
-}
-
-using namespace std;
-
-namespace BansheeEngine
-{
-	// Print out the FX AST, only for debug purposes
-	void SLFXDebugPrint(ASTFXNode* node, String indent)
-	{
-		LOGDBG(indent + "NODE " + toString(node->type));
-
-		for (int i = 0; i < node->options->count; i++)
-		{
-			OptionDataType odt = OPTION_LOOKUP[(int)node->options->entries[i].type].dataType;
-			if (odt == ODT_Complex)
-			{
-				LOGDBG(indent + toString(i) + ". " + toString(node->options->entries[i].type));
-				SLFXDebugPrint(node->options->entries[i].value.nodePtr, indent + "\t");
-				continue;
-			}
-
-			String value;
-			switch (odt)
-			{
-			case ODT_Bool:
-				value = toString(node->options->entries[i].value.intValue != 0);
-				break;
-			case ODT_Int:
-				value = toString(node->options->entries[i].value.intValue);
-				break;
-			case ODT_Float:
-				value = toString(node->options->entries[i].value.floatValue);
-				break;
-			case ODT_String:
-				value = node->options->entries[i].value.strValue;
-				break;
-			case ODT_Matrix:
-			{
-				Matrix4 mat4 = *(Matrix4*)(node->options->entries[i].value.matrixValue);
-				value = toString(mat4);
-			}
-				break;
-			}
-
-			LOGDBG(indent + toString(i) + ". " + toString(node->options->entries[i].type) + " = " + value);
-		}
-	}
-
-	BSLFXCompileResult BSLFXCompiler::compile(const String& source)
-	{
-		BSLFXCompileResult output;
-
-		String parsedSource = source;
-
-		ParseState* parseState = parseStateCreate();
-		parseFX(parseState, parsedSource.c_str());
-
-		if (parseState->hasError > 0)
-		{
-			output.errorMessage = parseState->errorMessage;
-			output.errorLine = parseState->errorLine;
-			output.errorColumn = parseState->errorColumn;
-
-			if(parseState->errorFile != nullptr)
-				output.errorFile = parseState->errorFile;
-
-			parseStateDelete(parseState);
-		}
-		else
-		{
-			// Only enable for debug purposes
-			//SLFXDebugPrint(parseState->rootNode, "");
-
-			Vector<String> codeBlocks;
-			CodeString* codeString = parseState->codeStrings;
-			while(codeString != nullptr)
-			{
-				while ((INT32)codeBlocks.size() <= codeString->index)
-					codeBlocks.push_back(String());
-
-				codeBlocks[codeString->index] = String(codeString->code, codeString->size);
-				codeString = codeString->next;
-			}
-
-			output = parseShader("Shader", parseState, codeBlocks);
-
-			StringStream gpuProgError;
-			bool hasError = false;
-			if (output.shader != nullptr)
-			{
-				TechniquePtr bestTechnique = output.shader->getBestTechnique();
-
-				if (bestTechnique != nullptr)
-				{
-					UINT32 numPasses = bestTechnique->getNumPasses();
-
-					for (UINT32 i = 0; i < numPasses; i++)
-					{
-						PassPtr pass = bestTechnique->getPass(i);
-
-						auto checkCompileStatus = [&](const String& prefix, const GpuProgramPtr& prog)
-						{
-							if (prog != nullptr)
-							{
-								prog->blockUntilCoreInitialized();
-
-								if (!prog->isCompiled())
-								{
-									hasError = true;
-									gpuProgError << prefix <<": " << prog->getCompileErrorMessage() << std::endl;
-								}
-							}
-						};
-
-						checkCompileStatus("Vertex program", pass->getVertexProgram());
-						checkCompileStatus("Fragment program", pass->getFragmentProgram());
-						checkCompileStatus("Geometry program", pass->getGeometryProgram());
-						checkCompileStatus("Hull program", pass->getHullProgram());
-						checkCompileStatus("Domain program", pass->getDomainProgram());
-						checkCompileStatus("Compute program", pass->getComputeProgram());
-					}
-				}
-			}
-
-			if (hasError)
-			{
-				output.shader = nullptr;
-				output.errorMessage = "Failed compiling GPU program(s): " + gpuProgError.str();
-				output.errorLine = 0;
-				output.errorColumn = 0;
-			}
-		}
-
-		return output;
-	}
-
-	void BSLFXCompiler::parseFX(ParseState* parseState, const char* source)
-	{
-		yyscan_t scanner;
-		YY_BUFFER_STATE state;
-
-		if (yylex_init_extra(parseState, &scanner))
-			return;
-
-		// If debug output from lexer is needed uncomment this and add %debug option to lexer file
-		//yyset_debug(true, scanner);
-
-		// If debug output from parser is needed uncomment this and add %debug option to parser file
-		//yydebug = true;
-
-		state = yy_scan_string(source, scanner);
-
-		if (yyparse(parseState, scanner))
-			return;
-
-		yy_delete_buffer(state, scanner);
-		yylex_destroy(scanner);
-	}
-
-	void BSLFXCompiler::getTechniqueIdentifier(ASTFXNode* technique, StringID& renderer, String& language)
-	{
-		renderer = RendererAny;
-		language = "Any";
-
-		for (int i = 0; i < technique->options->count; i++)
-		{
-			NodeOption* option = &technique->options->entries[i];
-
-			switch (option->type)
-			{
-			case OT_Renderer:
-				renderer = parseRenderer(removeQuotes(option->value.strValue));
-				break;
-			case OT_Language:
-				language = removeQuotes(option->value.strValue);
-				break;
-			}
-		}
-	}
-
-	bool BSLFXCompiler::doTechniquesMatch(ASTFXNode* into, ASTFXNode* from)
-	{
-		StringID intoRenderer = RendererAny;
-		String intoLanguage = "Any";
-
-		StringID fromRenderer = RendererAny;
-		String fromLanguage = "Any";
-
-		getTechniqueIdentifier(into, intoRenderer, intoLanguage);
-		getTechniqueIdentifier(from, fromRenderer, fromLanguage);
-
-		return (intoRenderer == fromRenderer || fromRenderer == RendererAny) && (intoLanguage == fromLanguage || fromLanguage == "Any");
-	}
-
-	StringID BSLFXCompiler::parseRenderer(const String& name)
-	{
-		if (name == "Any")
-			return RendererAny;
-		else if (name == "Default")
-			return RendererDefault;
-
-		return RendererAny;
-	}
-
-	void BSLFXCompiler::parseLanguage(const String& name, StringID& renderAPI, String& language)
-	{
-		if (name == "HLSL" || name == "HLSL11")
-		{
-			renderAPI = RenderAPIDX11;
-			language = "hlsl";
-		}
-		else if (name == "HLSL9")
-		{
-			renderAPI = RenderAPIDX9;
-			language = "hlsl9";
-		}
-		else if (name == "GLSL")
-		{
-			renderAPI = RenderAPIOpenGL;
-			language = "glsl";
-		}
-		else // "Any"
-		{
-			renderAPI = RenderAPIAny;
-			language = "";
-		}
-	}
-
-	GpuParamBlockUsage BSLFXCompiler::parseBlockUsage(BufferUsageValue usage)
-	{
-		if (usage == BUV_Dynamic)
-			return GPBU_DYNAMIC;
-
-		return GPBU_STATIC;
-	}
-
-	UINT32 BSLFXCompiler::parseFilterMode(FilterValue filter)
-	{
-		switch (filter)
-		{
-		case FV_Point:
-			return FO_POINT;
-		case FV_Linear:
-			return FO_LINEAR;
-		case FV_Anisotropic:
-			return FO_ANISOTROPIC;
-		case FV_PointCmp:
-			return FO_POINT | FO_USE_COMPARISON;
-		case FV_LinearCmp:
-			return FO_LINEAR | FO_USE_COMPARISON;
-		case FV_AnisotropicCmp:
-			return FO_ANISOTROPIC | FO_USE_COMPARISON;
-		}
-
-		return FO_NONE;
-	}
-
-	CompareFunction BSLFXCompiler::parseCompFunc(CompFuncValue compFunc)
-	{
-		switch (compFunc)
-		{
-		case CFV_Pass:
-			return CMPF_ALWAYS_PASS;
-		case CFV_Fail:
-			return CMPF_ALWAYS_FAIL;
-		case CFV_LT:
-			return CMPF_LESS;
-		case CFV_LTE:
-			return CMPF_LESS_EQUAL;
-		case CFV_EQ:
-			return CMPF_EQUAL;
-		case CFV_NEQ:
-			return CMPF_NOT_EQUAL;
-		case CFV_GT:
-			return CMPF_GREATER;
-		case CFV_GTE:
-			return CMPF_GREATER_EQUAL;
-		}
-
-		return CMPF_ALWAYS_PASS;
-	}
-
-	TextureAddressingMode BSLFXCompiler::parseAddrMode(AddrModeValue addrMode)
-	{
-		switch (addrMode)
-		{
-		case AMV_Wrap:
-			return TAM_WRAP;
-		case AMV_Mirror:
-			return TAM_MIRROR;
-		case AMV_Clamp:
-			return TAM_CLAMP;
-		case AMV_Border:
-			return TAM_BORDER;
-		}
-
-		return TAM_WRAP;
-	}
-
-	BlendFactor BSLFXCompiler::parseBlendFactor(OpValue factor)
-	{
-		switch (factor)
-		{
-		case OV_One:
-			return BF_ONE;
-		case OV_Zero:
-			return BF_ZERO;
-		case OV_DestColor:
-			return BF_DEST_COLOR;
-		case OV_SrcColor:
-			return BF_SOURCE_COLOR;
-		case OV_InvDestColor:
-			return BF_INV_DEST_COLOR;
-		case OV_InvSrcColor:
-			return BF_INV_SOURCE_COLOR;
-		case OV_DestAlpha:
-			return BF_DEST_ALPHA;
-		case OV_SrcAlpha:
-			return BF_SOURCE_ALPHA;
-		case OV_InvDestAlpha:
-			return BF_INV_DEST_ALPHA;
-		case OV_InvSrcAlpha:
-			return BF_INV_SOURCE_ALPHA;
-		}
-
-		return BF_ONE;
-	}
-
-	BlendOperation BSLFXCompiler::parseBlendOp(BlendOpValue op)
-	{
-		switch (op)
-		{
-		case BOV_Add:
-			return BO_ADD;
-		case BOV_Max:
-			return BO_MAX;
-		case BOV_Min:
-			return BO_MIN;
-		case BOV_Subtract:
-			return BO_SUBTRACT;
-		case BOV_RevSubtract:
-			return BO_REVERSE_SUBTRACT;
-		}
-
-		return BO_ADD;
-	}
-
-	void BSLFXCompiler::parseParamType(ParamType type, bool& isObjType, UINT32& typeId)
-	{
-		struct ParamData
-		{
-			UINT32 type;
-			bool isObjType;
-		};
-
-		static bool initialized = false;
-		static ParamData lookup[PT_Count];
-
-		if (!initialized)
-		{
-			lookup[PT_Float] = { { GPDT_FLOAT1 }, false };
-			lookup[PT_Float2] = { { GPDT_FLOAT2 }, false };
-			lookup[PT_Float3] = { { GPDT_FLOAT3 }, false };
-			lookup[PT_Float4] = { { GPDT_FLOAT4 }, false };
-
-			lookup[PT_Int] = { { GPDT_INT1 }, false };
-			lookup[PT_Int2] = { { GPDT_INT2 }, false };
-			lookup[PT_Int3] = { { GPDT_INT3 }, false };
-			lookup[PT_Int4] = { { GPDT_INT4 }, false };
-
-			lookup[PT_Mat2x2] = { { GPDT_MATRIX_2X2 }, false };
-			lookup[PT_Mat2x3] = { { GPDT_MATRIX_2X3 }, false };
-			lookup[PT_Mat2x4] = { { GPDT_MATRIX_2X4 }, false };
-
-			lookup[PT_Mat3x2] = { { GPDT_MATRIX_3X2 }, false };
-			lookup[PT_Mat3x3] = { { GPDT_MATRIX_3X3 }, false };
-			lookup[PT_Mat3x4] = { { GPDT_MATRIX_3X4 }, false };
-
-			lookup[PT_Mat4x2] = { { GPDT_MATRIX_4X2 }, false };
-			lookup[PT_Mat4x3] = { { GPDT_MATRIX_4X3 }, false };
-			lookup[PT_Mat4x4] = { { GPDT_MATRIX_4X4 }, false };
-
-			lookup[PT_Sampler1D] = { { GPOT_SAMPLER1D }, true };
-			lookup[PT_Sampler2D] = { { GPOT_SAMPLER2D }, true };
-			lookup[PT_Sampler3D] = { { GPOT_SAMPLER3D }, true };
-			lookup[PT_SamplerCUBE] = { { GPOT_SAMPLERCUBE }, true };
-			lookup[PT_Sampler2DMS] = { { GPOT_SAMPLER2DMS }, true };
-
-			lookup[PT_Texture1D] = { { GPOT_TEXTURE1D }, true };
-			lookup[PT_Texture2D] = { { GPOT_TEXTURE2D }, true };
-			lookup[PT_Texture3D] = { { GPOT_TEXTURE3D }, true };
-			lookup[PT_TextureCUBE] = { { GPOT_TEXTURECUBE }, true };
-			lookup[PT_Texture2DMS] = { { GPOT_TEXTURE2DMS }, true };
-
-			lookup[PT_ByteBuffer] = { { GPOT_BYTE_BUFFER }, true };
-			lookup[PT_StructBuffer] = { { GPOT_STRUCTURED_BUFFER }, true };
-			lookup[PT_TypedBufferRW] = { { GPOT_RWTYPED_BUFFER }, true };
-			lookup[PT_ByteBufferRW] = { { GPOT_RWBYTE_BUFFER }, true };
-			lookup[PT_StructBufferRW] = { { GPOT_RWSTRUCTURED_BUFFER }, true };
-			lookup[PT_AppendBuffer] = { { GPOT_RWAPPEND_BUFFER }, true };
-			lookup[PT_ConsumeBuffer] = { { GPOT_RWCONSUME_BUFFER }, true };
-
-			initialized = true;
-		}
-
-		isObjType = lookup[type].isObjType;
-		typeId = lookup[type].type;
-	}
-
-	StencilOperation BSLFXCompiler::parseStencilOp(OpValue op)
-	{
-		switch (op)
-		{
-		case OV_Keep:
-			return SOP_KEEP;
-		case OV_Zero:
-			return SOP_ZERO;
-		case OV_Replace:
-			return SOP_REPLACE;
-		case OV_Incr:
-			return SOP_INCREMENT;
-		case OV_Decr:
-			return SOP_DECREMENT;
-		case OV_IncrWrap:
-			return SOP_INCREMENT_WRAP;
-		case OV_DecrWrap:
-			return SOP_DECREMENT_WRAP;
-		case OV_Invert:
-			return SOP_INVERT;
-		}
-
-		return SOP_KEEP;
-	}
-
-	CullingMode BSLFXCompiler::parseCullMode(CullModeValue cm)
-	{
-		switch (cm)
-		{
-		case CMV_None:
-			return CULL_NONE;
-		case CMV_CW:
-			return CULL_CLOCKWISE;
-		case CMV_CCW:
-			return CULL_COUNTERCLOCKWISE;
-		}
-
-		return CULL_COUNTERCLOCKWISE;
-	}
-
-	PolygonMode BSLFXCompiler::parseFillMode(FillModeValue fm)
-	{
-		if (fm == FMV_Wire)
-			return PM_WIREFRAME;
-
-		return PM_SOLID;
-	}
-
-	void BSLFXCompiler::parseStencilFront(DEPTH_STENCIL_STATE_DESC& desc, ASTFXNode* stencilOpNode)
-	{
-		if (stencilOpNode == nullptr || stencilOpNode->type != NT_StencilOp)
-			return;
-
-		for (int i = 0; i < stencilOpNode->options->count; i++)
-		{
-			NodeOption* option = &stencilOpNode->options->entries[i];
-
-			switch (option->type)
-			{
-			case OT_Fail:
-				desc.frontStencilFailOp = parseStencilOp((OpValue)option->value.intValue);
-				break;
-			case OT_ZFail:
-				desc.frontStencilZFailOp = parseStencilOp((OpValue)option->value.intValue);
-				break;
-			case OT_PassOp:
-				desc.frontStencilPassOp = parseStencilOp((OpValue)option->value.intValue);
-				break;
-			case OT_CompareFunc:
-				desc.frontStencilComparisonFunc = parseCompFunc((CompFuncValue)option->value.intValue);
-				break;
-			}
-		}
-	}
-
-	void BSLFXCompiler::parseStencilBack(DEPTH_STENCIL_STATE_DESC& desc, ASTFXNode* stencilOpNode)
-	{
-		if (stencilOpNode == nullptr || stencilOpNode->type != NT_StencilOp)
-			return;
-
-		for (int i = 0; i < stencilOpNode->options->count; i++)
-		{
-			NodeOption* option = &stencilOpNode->options->entries[i];
-
-			switch (option->type)
-			{
-			case OT_Fail:
-				desc.backStencilFailOp = parseStencilOp((OpValue)option->value.intValue);
-				break;
-			case OT_ZFail:
-				desc.backStencilZFailOp = parseStencilOp((OpValue)option->value.intValue);
-				break;
-			case OT_PassOp:
-				desc.backStencilPassOp = parseStencilOp((OpValue)option->value.intValue);
-				break;
-			case OT_CompareFunc:
-				desc.backStencilComparisonFunc = parseCompFunc((CompFuncValue)option->value.intValue);
-				break;
-			}
-		}
-	}
-
-	void BSLFXCompiler::parseAddrMode(SAMPLER_STATE_DESC& desc, ASTFXNode* addrModeNode)
-	{
-		if (addrModeNode == nullptr || addrModeNode->type != NT_AddrMode)
-			return;
-
-		for (int i = 0; i < addrModeNode->options->count; i++)
-		{
-			NodeOption* option = &addrModeNode->options->entries[i];
-
-			switch (option->type)
-			{
-			case OT_U:
-				desc.addressMode.u = parseAddrMode((AddrModeValue)option->value.intValue);
-				break;
-			case OT_V:
-				desc.addressMode.v = parseAddrMode((AddrModeValue)option->value.intValue);
-				break;
-			case OT_W:
-				desc.addressMode.w = parseAddrMode((AddrModeValue)option->value.intValue);
-				break;
-			}
-		}
-	}
-
-	void BSLFXCompiler::parseColorBlendDef(RENDER_TARGET_BLEND_STATE_DESC& desc, ASTFXNode* blendDefNode)
-	{
-		if (blendDefNode == nullptr || blendDefNode->type != NT_BlendDef)
-			return;
-
-		for (int i = 0; i < blendDefNode->options->count; i++)
-		{
-			NodeOption* option = &blendDefNode->options->entries[i];
-
-			switch (option->type)
-			{
-			case OT_Source:
-				desc.srcBlend = parseBlendFactor((OpValue)option->value.intValue);
-				break;
-			case OT_Dest:
-				desc.dstBlend = parseBlendFactor((OpValue)option->value.intValue);
-				break;
-			case OT_Op:
-				desc.blendOp = parseBlendOp((BlendOpValue)option->value.intValue);
-				break;
-			}
-		}
-	}
-
-	void BSLFXCompiler::parseAlphaBlendDef(RENDER_TARGET_BLEND_STATE_DESC& desc, ASTFXNode* blendDefNode)
-	{
-		if (blendDefNode == nullptr || blendDefNode->type != NT_BlendDef)
-			return;
-
-		for (int i = 0; i < blendDefNode->options->count; i++)
-		{
-			NodeOption* option = &blendDefNode->options->entries[i];
-
-			switch (option->type)
-			{
-			case OT_Source:
-				desc.srcBlendAlpha = parseBlendFactor((OpValue)option->value.intValue);
-				break;
-			case OT_Dest:
-				desc.dstBlendAlpha = parseBlendFactor((OpValue)option->value.intValue);
-				break;
-			case OT_Op:
-				desc.blendOpAlpha = parseBlendOp((BlendOpValue)option->value.intValue);
-				break;
-			}
-		}
-	}
-
-	void BSLFXCompiler::parseRenderTargetBlendState(BLEND_STATE_DESC& desc, ASTFXNode* targetNode)
-	{
-		if (targetNode == nullptr || targetNode->type != NT_Target)
-			return;
-
-		UINT32 index = 0;
-
-		for (int i = 0; i < targetNode->options->count; i++)
-		{
-			NodeOption* option = &targetNode->options->entries[i];
-
-			switch (option->type)
-			{
-			case OT_Index:
-				index = option->value.intValue;
-				break;
-			}
-		}
-
-		if (index >= BS_MAX_MULTIPLE_RENDER_TARGETS)
-			return;
-
-		RENDER_TARGET_BLEND_STATE_DESC& rtDesc = desc.renderTargetDesc[index];
-		for (int i = 0; i < targetNode->options->count; i++)
-		{
-			NodeOption* option = &targetNode->options->entries[i];
-
-			switch (option->type)
-			{
-			case OT_Blend:
-				rtDesc.blendEnable = option->value.intValue > 0;
-				break;
-			case OT_Color:
-				parseColorBlendDef(rtDesc, option->value.nodePtr);
-				break;
-			case OT_Alpha:
-				parseAlphaBlendDef(rtDesc, option->value.nodePtr);
-				break;
-			case OT_WriteMask:
-				rtDesc.renderTargetWriteMask = option->value.intValue;
-				break;
-			}
-		}
-	}
-
-	bool BSLFXCompiler::parseBlendState(BLEND_STATE_DESC& desc, ASTFXNode* passNode)
-	{
-		if (passNode == nullptr || (passNode->type != NT_Pass && passNode->type != NT_Technique))
-			return false;
-
-		bool default = true;
-
-		for (int i = 0; i < passNode->options->count; i++)
-		{
-			NodeOption* option = &passNode->options->entries[i];
-
-			switch (option->type)
-			{
-			case OT_AlphaToCoverage:
-				desc.alphaToCoverageEnable = option->value.intValue > 0;
-				default = false;
-				break;
-			case OT_IndependantBlend:
-				desc.independantBlendEnable = option->value.intValue > 0;
-				default = false;
-				break;
-			case OT_Target:
-				parseRenderTargetBlendState(desc, option->value.nodePtr);
-				default = false;
-				break;
-			}
-		}
-
-		return !default;
-	}
-
-	bool BSLFXCompiler::parseRasterizerState(RASTERIZER_STATE_DESC& desc, ASTFXNode* passNode)
-	{
-		if (passNode == nullptr || (passNode->type != NT_Pass && passNode->type != NT_Technique))
-			return false;
-
-		bool default = true;
-
-		for (int i = 0; i < passNode->options->count; i++)
-		{
-			NodeOption* option = &passNode->options->entries[i];
-
-			switch (option->type)
-			{
-			case OT_FillMode:
-				desc.polygonMode = parseFillMode((FillModeValue)option->value.intValue);
-				default = false;
-				break;
-			case OT_CullMode:
-				desc.cullMode = parseCullMode((CullModeValue)option->value.intValue);
-				default = false;
-				break;
-			case OT_DepthBias:
-				desc.depthBias = option->value.floatValue;
-				default = false;
-				break;
-			case OT_SDepthBias:
-				desc.slopeScaledDepthBias = option->value.floatValue;
-				default = false;
-				break;
-			case OT_DepthClip:
-				desc.depthClipEnable = option->value.intValue > 0;
-				default = false;
-				break;
-			case OT_Scissor:
-				desc.scissorEnable = option->value.intValue > 0;
-				default = false;
-				break;
-			case OT_Multisample:
-				desc.multisampleEnable = option->value.intValue > 0;
-				default = false;
-				break;
-			case OT_AALine:
-				desc.antialiasedLineEnable = option->value.intValue > 0;
-				default = false;
-				break;
-			}
-		}
-
-		return !default;
-	}
-
-	bool BSLFXCompiler::parseDepthStencilState(DEPTH_STENCIL_STATE_DESC& desc, ASTFXNode* passNode)
-	{
-		if (passNode == nullptr || (passNode->type != NT_Pass && passNode->type != NT_Technique))
-			return false;
-
-		bool default = true;
-
-		for (int i = 0; i < passNode->options->count; i++)
-		{
-			NodeOption* option = &passNode->options->entries[i];
-
-			switch (option->type)
-			{
-			case OT_DepthRead:
-				desc.depthReadEnable = option->value.intValue > 0;
-				default = false;
-				break;
-			case OT_DepthWrite:
-				desc.depthWriteEnable = option->value.intValue > 0;
-				default = false;
-				break;
-			case OT_CompareFunc:
-				desc.depthComparisonFunc = parseCompFunc((CompFuncValue)option->value.intValue);
-				default = false;
-				break;
-			case OT_Stencil:
-				desc.stencilEnable = option->value.intValue > 0;
-				default = false;
-				break;
-			case OT_StencilReadMask:
-				desc.stencilReadMask = (UINT8)option->value.intValue;
-				default = false;
-				break;
-			case OT_StencilWriteMask:
-				desc.stencilWriteMask = (UINT8)option->value.intValue;
-				default = false;
-				break;
-			case OT_StencilOpFront:
-				parseStencilFront(desc, option->value.nodePtr);
-				default = false;
-				break;
-			case OT_StencilOpBack:
-				parseStencilBack(desc, option->value.nodePtr);
-				default = false;
-				break;
-			}
-		}
-
-		return !default;
-	}
-
-	SamplerStatePtr BSLFXCompiler::parseSamplerState(ASTFXNode* samplerStateNode)
-	{
-		if (samplerStateNode == nullptr || samplerStateNode->type != NT_SamplerState)
-			return nullptr;
-
-		SAMPLER_STATE_DESC desc;
-		bool default = true;
-
-		for (int i = 0; i < samplerStateNode->options->count; i++)
-		{
-			NodeOption* option = &samplerStateNode->options->entries[i];
-
-			switch (option->type)
-			{
-			case OT_AddrMode:
-				parseAddrMode(desc, option->value.nodePtr);
-				default = false;
-				break;
-			case OT_MinFilter:
-				desc.minFilter = (FilterOptions)parseFilterMode((FilterValue)option->value.intValue);
-				default = false;
-				break;
-			case OT_MagFilter:
-				desc.magFilter = (FilterOptions)parseFilterMode((FilterValue)option->value.intValue);
-				default = false;
-				break;
-			case OT_MipFilter:
-				desc.mipFilter = (FilterOptions)parseFilterMode((FilterValue)option->value.intValue);
-				default = false;
-				break;
-			case OT_MaxAniso:
-				desc.maxAniso = option->value.intValue;
-				default = false;
-				break;
-			case OT_MipBias:
-				desc.mipmapBias = option->value.floatValue;
-				default = false;
-				break;
-			case OT_MipMin:
-				desc.mipMin = option->value.floatValue;
-				default = false;
-				break;
-			case OT_MipMax:
-				desc.mipMax = option->value.floatValue;
-				default = false;
-				break;
-			case OT_BorderColor:
-				desc.borderColor = Color(option->value.matrixValue[0], option->value.matrixValue[1],
-					option->value.matrixValue[2], option->value.matrixValue[3]);
-				default = false;
-				break;
-			case OT_CompareFunc:
-				desc.comparisonFunc = parseCompFunc((CompFuncValue)option->value.intValue);
-				default = false;
-				break;
-			}
-		}
-
-		if (default)
-			return nullptr;
-
-		return SamplerState::create(desc);
-	}
-
-	void BSLFXCompiler::parseCodeBlock(ASTFXNode* codeNode, const Vector<String>& codeBlocks, PassData& passData)
-	{
-		if (codeNode == nullptr || (codeNode->type != NT_CodeCommon && codeNode->type != NT_CodeVertex && 
-			codeNode->type != NT_CodeFragment && codeNode->type != NT_CodeGeometry && codeNode->type != NT_CodeHull &&
-			codeNode->type != NT_CodeDomain && codeNode->type != NT_CodeCompute))
-		{
-			return;
-		}
-
-		UINT32 index = (UINT32)-1;
-		for (int j = 0; j < codeNode->options->count; j++)
-		{
-			if (codeNode->options->entries[j].type == OT_Index)
-				index = codeNode->options->entries[j].value.intValue;
-		}
-
-		if (index != (UINT32)-1 && index < (UINT32)codeBlocks.size())
-		{
-			switch (codeNode->type)
-			{
-			case NT_CodeVertex:
-				passData.vertexCode += codeBlocks[index];
-				break;
-			case NT_CodeFragment:
-				passData.fragmentCode += codeBlocks[index];
-				break;
-			case NT_CodeGeometry:
-				passData.geometryCode += codeBlocks[index];
-				break;
-			case NT_CodeHull:
-				passData.hullCode += codeBlocks[index];
-				break;
-			case NT_CodeDomain:
-				passData.domainCode += codeBlocks[index];
-				break;
-			case NT_CodeCompute:
-				passData.computeCode += codeBlocks[index];
-				break;
-			case NT_CodeCommon:
-				passData.commonCode += codeBlocks[index];
-				break;
-			}
-		}
-	}
-
-	void BSLFXCompiler::parsePass(ASTFXNode* passNode, const Vector<String>& codeBlocks, PassData& passData)
-	{
-		if (passNode == nullptr || passNode->type != NT_Pass)
-			return;
-
-		passData.blendIsDefault &= !parseBlendState(passData.blendDesc, passNode);
-		passData.rasterizerIsDefault &= !parseRasterizerState(passData.rasterizerDesc, passNode);
-		passData.depthStencilIsDefault &= !parseDepthStencilState(passData.depthStencilDesc, passNode);
-
-		for (int i = 0; i < passNode->options->count; i++)
-		{
-			NodeOption* option = &passNode->options->entries[i];
-
-			switch (option->type)
-			{
-			case OT_StencilRef:
-				passData.stencilRefValue = option->value.intValue;
-				break;
-			case OT_Code:
-				parseCodeBlock(option->value.nodePtr, codeBlocks, passData);
-				break;
-			}
-		}
-	}
-
-	void BSLFXCompiler::parseTechnique(ASTFXNode* techniqueNode, const Vector<String>& codeBlocks, TechniqueData& techniqueData)
-	{
-		if (techniqueNode == nullptr || techniqueNode->type != NT_Technique)
-			return;
-
-		UINT32 nextPassIdx = 0;
-		// Go in reverse because options are added in reverse order during parsing
-		for (int i = techniqueNode->options->count - 1; i >= 0; i--)
-		{
-			NodeOption* option = &techniqueNode->options->entries[i];
-
-			switch (option->type)
-			{
-			case OT_Pass:
-			{
-				UINT32 passIdx = nextPassIdx;
-
-				ASTFXNode* passNode = option->value.nodePtr;
-				for (int j = 0; j < passNode->options->count; j++)
-				{
-					NodeOption* passOption = &passNode->options->entries[j];
-
-					switch (passOption->type)
-					{
-					case OT_Index:
-						passIdx = passOption->value.intValue;
-						break;
-					}
-				}
-
-				PassData* passData = nullptr;
-				for (auto& entry : techniqueData.passes)
-				{
-					if (entry.seqIdx == passIdx)
-						passData = &entry;
-				}
-
-				if (passData == nullptr)
-				{
-					techniqueData.passes.push_back(PassData());
-					passData = &techniqueData.passes.back();
-
-					passData->seqIdx = passIdx;
-				}
-
-				nextPassIdx = std::max(nextPassIdx, passIdx) + 1;
-
-				passData->blendIsDefault &= !parseBlendState(passData->blendDesc, techniqueNode);
-				passData->rasterizerIsDefault &= !parseRasterizerState(passData->rasterizerDesc, techniqueNode);
-				passData->depthStencilIsDefault &= !parseDepthStencilState(passData->depthStencilDesc, techniqueNode);
-
-				passData->vertexCode = techniqueData.commonPassData.vertexCode + passData->vertexCode;
-				passData->fragmentCode = techniqueData.commonPassData.fragmentCode + passData->fragmentCode;
-				passData->geometryCode = techniqueData.commonPassData.geometryCode + passData->geometryCode;
-				passData->hullCode = techniqueData.commonPassData.hullCode + passData->hullCode;
-				passData->domainCode = techniqueData.commonPassData.domainCode + passData->domainCode;
-				passData->commonCode = techniqueData.commonPassData.commonCode + passData->commonCode;
-				
-				parsePass(passNode, codeBlocks, *passData);
-			}
-				break;
-			case OT_Renderer:
-				techniqueData.renderer = parseRenderer(removeQuotes(option->value.strValue));
-				break;
-			case OT_Language:
-				parseLanguage(removeQuotes(option->value.strValue), techniqueData.renderAPI, techniqueData.language);
-				break;
-			case OT_Code:
-				parseCodeBlock(option->value.nodePtr, codeBlocks, techniqueData.commonPassData);
-				break;
-			}
-		}
-	}
-
-	void BSLFXCompiler::parseParameters(SHADER_DESC& desc, ASTFXNode* parametersNode)
-	{
-		if (parametersNode == nullptr || parametersNode->type != NT_Parameters)
-			return;
-
-		for (int i = 0; i < parametersNode->options->count; i++)
-		{
-			NodeOption* option = &parametersNode->options->entries[i];
-
-			if (option->type != OT_Parameter)
-				continue;
-
-			ASTFXNode* parameter = option->value.nodePtr;
-
-			String name;
-			String alias;
-
-			UINT32 typeId = 0;
-			bool isObjType = false;
-			StringID semantic;
-			SamplerStatePtr samplerState = nullptr;
-			float defaultValue[16];
-			HTexture defaultTexture;
-			bool hasDefaultValue = false;
-			for (int j = 0; j < parameter->options->count; j++)
-			{
-				NodeOption* paramOption = &parameter->options->entries[j];
-
-				switch (paramOption->type)
-				{
-				case OT_Identifier:
-					name = paramOption->value.strValue;
-					break;
-				case OT_Alias:
-					alias = removeQuotes(paramOption->value.strValue);
-					break;
-				case OT_ParamType:
-					parseParamType((ParamType)paramOption->value.intValue, isObjType, typeId);
-					break;
-				case OT_ParamValue:
-					memcpy(defaultValue, paramOption->value.matrixValue, sizeof(defaultValue));
-					hasDefaultValue = true;
-					break;
-				case OT_ParamStrValue:
-				{
-					String defaultTextureName = removeQuotes(paramOption->value.strValue);
-					defaultTexture = getBuiltinTexture(defaultTextureName);
-					hasDefaultValue = true;
-				}
-					break;
-				case OT_Auto:
-					semantic = removeQuotes(paramOption->value.strValue);
-					break;
-				case OT_SamplerState:
-					samplerState = parseSamplerState(paramOption->value.nodePtr);
-					break;
-				}
-			}
-
-			if (name.empty())
-				continue;
-
-			auto addParameter = [&](const String& paramName, const String& gpuVarName)
-			{
-				if (isObjType)
-				{
-					GpuParamObjectType objType = (GpuParamObjectType)typeId;
-
-					if (Shader::isSampler(objType))
-					{
-						if(hasDefaultValue)
-							desc.addParameter(paramName, gpuVarName, objType, samplerState, semantic);
-						else
-							desc.addParameter(paramName, gpuVarName, objType, semantic);
-					}
-					else if(Shader::isTexture(objType))
-					{
-						if(hasDefaultValue)
-							desc.addParameter(paramName, gpuVarName, objType, defaultTexture, semantic);
-						else
-							desc.addParameter(paramName, gpuVarName, objType, semantic);
-					}
-					else
-						desc.addParameter(paramName, gpuVarName, objType, semantic);
-				}
-				else
-				{
-					if (hasDefaultValue)
-						desc.addParameter(paramName, gpuVarName, (GpuParamDataType)typeId, semantic, 1, 0, (UINT8*)defaultValue);
-					else
-						desc.addParameter(paramName, gpuVarName, (GpuParamDataType)typeId, semantic);
-				}
-			};
-
-			addParameter(name, name);
-
-			if (!alias.empty())
-				addParameter(name, alias);
-		}
-	}
-
-	void BSLFXCompiler::parseBlocks(SHADER_DESC& desc, ASTFXNode* blocksNode)
-	{
-		if (blocksNode == nullptr || blocksNode->type != NT_Blocks)
-			return;
-
-		for (int i = 0; i < blocksNode->options->count; i++)
-		{
-			NodeOption* option = &blocksNode->options->entries[i];
-
-			if (option->type != OT_Block)
-				continue;
-
-			ASTFXNode* parameter = option->value.nodePtr;
-
-			String name;
-			bool shared = false;
-			GpuParamBlockUsage usage = GPBU_STATIC;
-			StringID semantic;
-
-			for (int j = 0; j < parameter->options->count; j++)
-			{
-				NodeOption* paramOption = &parameter->options->entries[j];
-
-				switch (paramOption->type)
-				{
-				case OT_Identifier:
-					name = paramOption->value.strValue;
-					break;
-				case OT_Shared:
-					shared = paramOption->value.intValue > 0;
-					break;
-				case OT_Usage:
-					usage = parseBlockUsage((BufferUsageValue)paramOption->value.intValue);
-					break;
-				case OT_Auto:
-					semantic = removeQuotes(paramOption->value.strValue);
-					break;
-				}
-			}
-
-			if (name.empty())
-				continue;
-
-			desc.setParamBlockAttribs(name, shared, usage, semantic);
-		}
-	}
-
-	BSLFXCompileResult BSLFXCompiler::parseShader(const String& name, ParseState* parseState, Vector<String>& codeBlocks)
-	{
-		BSLFXCompileResult output;
-
-		if (parseState->rootNode == nullptr || parseState->rootNode->type != NT_Shader)
-		{
-			output.errorMessage = "Root not is null or not a shader.";
-			return output;
-		}
-
-		SHADER_DESC shaderDesc;
-		Vector<pair<ASTFXNode*, TechniqueData>> techniqueData;
-
-		// Go in reverse because options are added in reverse order during parsing
-		for (int i = parseState->rootNode->options->count - 1; i >= 0; i--)
-		{
-			NodeOption* option = &parseState->rootNode->options->entries[i];
-
-			switch (option->type)
-			{
-			case OT_Separable:
-				shaderDesc.separablePasses = option->value.intValue > 1;
-				break;
-			case OT_Queue:
-				shaderDesc.queuePriority = option->value.intValue;
-				break;
-			case OT_Priority:
-				shaderDesc.queuePriority = option->value.intValue;
-				break;
-			case OT_Transparent:
-				shaderDesc.flags |= (UINT32)ShaderFlags::Transparent;
-				break;
-			case OT_Technique:
-			{
-				auto iterFind = std::find_if(techniqueData.begin(), techniqueData.end(), 
-					[&] (auto x)
-				{
-					return doTechniquesMatch(x.first, option->value.nodePtr);
-				});
-
-				TechniqueData* data = nullptr;
-				if (iterFind != techniqueData.end())
-					data = &iterFind->second;
-				else
-				{
-					techniqueData.push_back(std::make_pair(option->value.nodePtr, TechniqueData()));
-					data = &techniqueData.back().second;
-				}
-
-				parseTechnique(option->value.nodePtr, codeBlocks, *data);
-				break;
-			}
-			case OT_Parameters:
-				parseParameters(shaderDesc, option->value.nodePtr);
-				break;
-			case OT_Blocks:
-				parseBlocks(shaderDesc, option->value.nodePtr);
-				break;
-			}
-		}
-
-		Vector<TechniquePtr> techniques;
-		for(auto& entry : techniqueData)
-		{
-			const TechniqueData& techniqueData = entry.second;
-
-			Map<UINT32, PassPtr, std::greater<UINT32>> passes;
-			for (auto& passData : entry.second.passes)
-			{
-				PASS_DESC passDesc;
-
-				if (!passData.blendIsDefault)
-					passDesc.blendState = BlendState::create(passData.blendDesc);
-
-				if (!passData.rasterizerIsDefault)
-					passDesc.rasterizerState = RasterizerState::create(passData.rasterizerDesc);
-
-				if (!passData.depthStencilIsDefault)
-					passDesc.depthStencilState = DepthStencilState::create(passData.depthStencilDesc);
-
-				if (!passData.vertexCode.empty())
-				{
-					passDesc.vertexProgram = GpuProgram::create(passData.commonCode + passData.vertexCode, "main", 
-						techniqueData.language, GPT_VERTEX_PROGRAM, getProfile(techniqueData.renderAPI, GPT_VERTEX_PROGRAM));
-				}
-
-				if (!passData.fragmentCode.empty())
-				{
-					passDesc.fragmentProgram = GpuProgram::create(passData.commonCode + passData.fragmentCode, "main", 
-						techniqueData.language, GPT_FRAGMENT_PROGRAM, getProfile(techniqueData.renderAPI, GPT_FRAGMENT_PROGRAM));
-				}
-
-				if (!passData.geometryCode.empty())
-				{
-					passDesc.geometryProgram = GpuProgram::create(passData.commonCode + passData.geometryCode, "main", 
-						techniqueData.language, GPT_GEOMETRY_PROGRAM, getProfile(techniqueData.renderAPI, GPT_GEOMETRY_PROGRAM));
-				}
-
-				if (!passData.hullCode.empty())
-				{
-					passDesc.hullProgram = GpuProgram::create(passData.commonCode + passData.hullCode, "main", 
-						techniqueData.language, GPT_HULL_PROGRAM, getProfile(techniqueData.renderAPI, GPT_HULL_PROGRAM));
-				}
-
-				if (!passData.domainCode.empty())
-				{
-					passDesc.domainProgram = GpuProgram::create(passData.commonCode + passData.domainCode, "main", 
-						techniqueData.language, GPT_DOMAIN_PROGRAM, getProfile(techniqueData.renderAPI, GPT_DOMAIN_PROGRAM));
-				}
-
-				if (!passData.computeCode.empty())
-				{
-					passDesc.computeProgram = GpuProgram::create(passData.commonCode + passData.computeCode, "main", 
-						techniqueData.language, GPT_COMPUTE_PROGRAM, getProfile(techniqueData.renderAPI, GPT_COMPUTE_PROGRAM));
-				}
-
-				passDesc.stencilRefValue = passData.stencilRefValue;
-
-				PassPtr pass = Pass::create(passDesc);
-				if (pass != nullptr)
-					passes[passData.seqIdx] = pass;
-			}
-
-			Vector<PassPtr> orderedPasses;
-			for (auto& KVP : passes)
-				orderedPasses.push_back(KVP.second);
-
-			if (orderedPasses.size() > 0)
-			{
-				TechniquePtr technique = Technique::create(techniqueData.renderAPI, techniqueData.renderer, orderedPasses);
-				techniques.push_back(technique);
-			}
-		}
-
-		Vector<String> includes;
-		IncludeLink* includeLink = parseState->includes;
-		while(includeLink != nullptr)
-		{
-			String includeFilename = includeLink->data->filename;
-
-			auto iterFind = std::find(includes.begin(), includes.end(), includeFilename);
-			if (iterFind == includes.end())
-				includes.push_back(includeFilename);
-
-			includeLink = includeLink->next;
-		}
-
-		parseStateDelete(parseState);
-
-		output.shader = Shader::_createPtr(name, shaderDesc, techniques);
-		output.shader->setIncludeFiles(includes);
-
-		return output;
-	}
-
-	String BSLFXCompiler::removeQuotes(const char* input)
-	{
-		UINT32 len = (UINT32)strlen(input);
-		String output(len - 2, ' ');
-
-		for (UINT32 i = 0; i < (len - 2); i++)
-			output[i] = input[i + 1];
-
-		return output;
-	}
-
-	GpuProgramProfile BSLFXCompiler::getProfile(const StringID& renderAPI, GpuProgramType type)
-	{
-		StringID target = renderAPI;
-		if (target == RenderAPIAny)
-			target = RenderAPICore::instance().getName();
-
-		if (target == RenderAPIDX11 || target == RenderAPIOpenGL)
-		{
-			switch (type)
-			{
-			case GPT_VERTEX_PROGRAM:
-				return GPP_VS_5_0;
-			case GPT_FRAGMENT_PROGRAM:
-				return GPP_FS_5_0;
-			case GPT_GEOMETRY_PROGRAM:
-				return GPP_GS_5_0;
-			case GPT_HULL_PROGRAM:
-				return GPP_HS_5_0;
-			case GPT_DOMAIN_PROGRAM:
-				return GPP_DS_5_0;
-			case GPT_COMPUTE_PROGRAM:
-				return GPP_CS_5_0;
-			}
-		}
-		else if (target == RenderAPIDX9)
-		{
-			switch (type)
-			{
-			case GPT_VERTEX_PROGRAM:
-				return GPP_VS_3_0;
-			case GPT_FRAGMENT_PROGRAM:
-				return GPP_FS_3_0;
-			}
-		}
-
-		return GPP_NONE;
-	}
-
-	HTexture BSLFXCompiler::getBuiltinTexture(const String& name)
-	{
-		if (StringUtil::compare(name, String("white"), false) == 0)
-			return BuiltinResources::getTexture(BuiltinTexture::White);
-		else if (StringUtil::compare(name, String("black"), false) == 0)
-			return BuiltinResources::getTexture(BuiltinTexture::Black);
-		else if (StringUtil::compare(name, String("normal"), false) == 0)
-			return BuiltinResources::getTexture(BuiltinTexture::Normal);
-
-		return HTexture();
-	}
+//********************************** Banshee Engine (www.banshee3d.com) **************************************************//
+//**************** Copyright (c) 2016 Marko Pintera ([email protected]). All rights reserved. **********************//
+#include "BsSLFXCompiler.h"
+#include "BsGpuProgram.h"
+#include <regex>
+#include "BsShader.h"
+#include "BsTechnique.h"
+#include "BsPass.h"
+#include "BsSamplerState.h"
+#include "BsRenderAPI.h"
+#include "BsDebug.h"
+#include "BsShaderManager.h"
+#include "BsShaderInclude.h"
+#include "BsMatrix4.h"
+#include "BsBuiltinResources.h"
+
+extern "C" {
+#include "BsMMAlloc.h"
+#include "BsParserFX.h"
+#include "BsLexerFX.h"
+}
+
+using namespace std;
+
+namespace BansheeEngine
+{
+	// Print out the FX AST, only for debug purposes
+	void SLFXDebugPrint(ASTFXNode* node, String indent)
+	{
+		LOGDBG(indent + "NODE " + toString(node->type));
+
+		for (int i = 0; i < node->options->count; i++)
+		{
+			OptionDataType odt = OPTION_LOOKUP[(int)node->options->entries[i].type].dataType;
+			if (odt == ODT_Complex)
+			{
+				LOGDBG(indent + toString(i) + ". " + toString(node->options->entries[i].type));
+				SLFXDebugPrint(node->options->entries[i].value.nodePtr, indent + "\t");
+				continue;
+			}
+
+			String value;
+			switch (odt)
+			{
+			case ODT_Bool:
+				value = toString(node->options->entries[i].value.intValue != 0);
+				break;
+			case ODT_Int:
+				value = toString(node->options->entries[i].value.intValue);
+				break;
+			case ODT_Float:
+				value = toString(node->options->entries[i].value.floatValue);
+				break;
+			case ODT_String:
+				value = node->options->entries[i].value.strValue;
+				break;
+			case ODT_Matrix:
+			{
+				Matrix4 mat4 = *(Matrix4*)(node->options->entries[i].value.matrixValue);
+				value = toString(mat4);
+			}
+				break;
+			}
+
+			LOGDBG(indent + toString(i) + ". " + toString(node->options->entries[i].type) + " = " + value);
+		}
+	}
+
+	BSLFXCompileResult BSLFXCompiler::compile(const String& source, const UnorderedMap<String, String>& defines)
+	{
+		BSLFXCompileResult output;
+
+		String parsedSource = source;
+
+		ParseState* parseState = parseStateCreate();
+		for(auto& define : defines)
+		{
+			if (define.first.size() == 0)
+				continue;
+
+			addDefine(parseState, define.first.c_str());
+
+			if(define.second.size() > 0)
+				addDefineExpr(parseState, define.second.c_str());
+		}
+
+		parseFX(parseState, parsedSource.c_str());
+
+		if (parseState->hasError > 0)
+		{
+			output.errorMessage = parseState->errorMessage;
+			output.errorLine = parseState->errorLine;
+			output.errorColumn = parseState->errorColumn;
+
+			if(parseState->errorFile != nullptr)
+				output.errorFile = parseState->errorFile;
+
+			parseStateDelete(parseState);
+		}
+		else
+		{
+			// Only enable for debug purposes
+			//SLFXDebugPrint(parseState->rootNode, "");
+
+			Vector<String> codeBlocks;
+			CodeString* codeString = parseState->codeStrings;
+			while(codeString != nullptr)
+			{
+				while ((INT32)codeBlocks.size() <= codeString->index)
+					codeBlocks.push_back(String());
+
+				codeBlocks[codeString->index] = String(codeString->code, codeString->size);
+				codeString = codeString->next;
+			}
+
+			output = parseShader("Shader", parseState, codeBlocks);
+
+			StringStream gpuProgError;
+			bool hasError = false;
+			if (output.shader != nullptr)
+			{
+				TechniquePtr bestTechnique = output.shader->getBestTechnique();
+
+				if (bestTechnique != nullptr)
+				{
+					UINT32 numPasses = bestTechnique->getNumPasses();
+
+					for (UINT32 i = 0; i < numPasses; i++)
+					{
+						PassPtr pass = bestTechnique->getPass(i);
+
+						auto checkCompileStatus = [&](const String& prefix, const GpuProgramPtr& prog)
+						{
+							if (prog != nullptr)
+							{
+								prog->blockUntilCoreInitialized();
+
+								if (!prog->isCompiled())
+								{
+									hasError = true;
+									gpuProgError << prefix <<": " << prog->getCompileErrorMessage() << std::endl;
+								}
+							}
+						};
+
+						checkCompileStatus("Vertex program", pass->getVertexProgram());
+						checkCompileStatus("Fragment program", pass->getFragmentProgram());
+						checkCompileStatus("Geometry program", pass->getGeometryProgram());
+						checkCompileStatus("Hull program", pass->getHullProgram());
+						checkCompileStatus("Domain program", pass->getDomainProgram());
+						checkCompileStatus("Compute program", pass->getComputeProgram());
+					}
+				}
+			}
+
+			if (hasError)
+			{
+				output.shader = nullptr;
+				output.errorMessage = "Failed compiling GPU program(s): " + gpuProgError.str();
+				output.errorLine = 0;
+				output.errorColumn = 0;
+			}
+		}
+
+		return output;
+	}
+
+	void BSLFXCompiler::parseFX(ParseState* parseState, const char* source)
+	{
+		yyscan_t scanner;
+		YY_BUFFER_STATE state;
+
+		if (yylex_init_extra(parseState, &scanner))
+			return;
+
+		// If debug output from lexer is needed uncomment this and add %debug option to lexer file
+		//yyset_debug(true, scanner);
+
+		// If debug output from parser is needed uncomment this and add %debug option to parser file
+		//yydebug = true;
+
+		state = yy_scan_string(source, scanner);
+
+		if (yyparse(parseState, scanner))
+			return;
+
+		yy_delete_buffer(state, scanner);
+		yylex_destroy(scanner);
+	}
+
+	void BSLFXCompiler::getTechniqueIdentifier(ASTFXNode* technique, StringID& renderer, String& language)
+	{
+		renderer = RendererAny;
+		language = "Any";
+
+		for (int i = 0; i < technique->options->count; i++)
+		{
+			NodeOption* option = &technique->options->entries[i];
+
+			switch (option->type)
+			{
+			case OT_Renderer:
+				renderer = parseRenderer(removeQuotes(option->value.strValue));
+				break;
+			case OT_Language:
+				language = removeQuotes(option->value.strValue);
+				break;
+			}
+		}
+	}
+
+	bool BSLFXCompiler::doTechniquesMatch(ASTFXNode* into, ASTFXNode* from)
+	{
+		StringID intoRenderer = RendererAny;
+		String intoLanguage = "Any";
+
+		StringID fromRenderer = RendererAny;
+		String fromLanguage = "Any";
+
+		getTechniqueIdentifier(into, intoRenderer, intoLanguage);
+		getTechniqueIdentifier(from, fromRenderer, fromLanguage);
+
+		return (intoRenderer == fromRenderer || fromRenderer == RendererAny) && (intoLanguage == fromLanguage || fromLanguage == "Any");
+	}
+
+	StringID BSLFXCompiler::parseRenderer(const String& name)
+	{
+		if (name == "Any")
+			return RendererAny;
+		else if (name == "Default")
+			return RendererDefault;
+
+		return RendererAny;
+	}
+
+	void BSLFXCompiler::parseLanguage(const String& name, StringID& renderAPI, String& language)
+	{
+		if (name == "HLSL" || name == "HLSL11")
+		{
+			renderAPI = RenderAPIDX11;
+			language = "hlsl";
+		}
+		else if (name == "HLSL9")
+		{
+			renderAPI = RenderAPIDX9;
+			language = "hlsl9";
+		}
+		else if (name == "GLSL")
+		{
+			renderAPI = RenderAPIOpenGL;
+			language = "glsl";
+		}
+		else // "Any"
+		{
+			renderAPI = RenderAPIAny;
+			language = "";
+		}
+	}
+
+	GpuParamBlockUsage BSLFXCompiler::parseBlockUsage(BufferUsageValue usage)
+	{
+		if (usage == BUV_Dynamic)
+			return GPBU_DYNAMIC;
+
+		return GPBU_STATIC;
+	}
+
+	UINT32 BSLFXCompiler::parseFilterMode(FilterValue filter)
+	{
+		switch (filter)
+		{
+		case FV_Point:
+			return FO_POINT;
+		case FV_Linear:
+			return FO_LINEAR;
+		case FV_Anisotropic:
+			return FO_ANISOTROPIC;
+		case FV_PointCmp:
+			return FO_POINT | FO_USE_COMPARISON;
+		case FV_LinearCmp:
+			return FO_LINEAR | FO_USE_COMPARISON;
+		case FV_AnisotropicCmp:
+			return FO_ANISOTROPIC | FO_USE_COMPARISON;
+		}
+
+		return FO_NONE;
+	}
+
+	CompareFunction BSLFXCompiler::parseCompFunc(CompFuncValue compFunc)
+	{
+		switch (compFunc)
+		{
+		case CFV_Pass:
+			return CMPF_ALWAYS_PASS;
+		case CFV_Fail:
+			return CMPF_ALWAYS_FAIL;
+		case CFV_LT:
+			return CMPF_LESS;
+		case CFV_LTE:
+			return CMPF_LESS_EQUAL;
+		case CFV_EQ:
+			return CMPF_EQUAL;
+		case CFV_NEQ:
+			return CMPF_NOT_EQUAL;
+		case CFV_GT:
+			return CMPF_GREATER;
+		case CFV_GTE:
+			return CMPF_GREATER_EQUAL;
+		}
+
+		return CMPF_ALWAYS_PASS;
+	}
+
+	TextureAddressingMode BSLFXCompiler::parseAddrMode(AddrModeValue addrMode)
+	{
+		switch (addrMode)
+		{
+		case AMV_Wrap:
+			return TAM_WRAP;
+		case AMV_Mirror:
+			return TAM_MIRROR;
+		case AMV_Clamp:
+			return TAM_CLAMP;
+		case AMV_Border:
+			return TAM_BORDER;
+		}
+
+		return TAM_WRAP;
+	}
+
+	BlendFactor BSLFXCompiler::parseBlendFactor(OpValue factor)
+	{
+		switch (factor)
+		{
+		case OV_One:
+			return BF_ONE;
+		case OV_Zero:
+			return BF_ZERO;
+		case OV_DestColor:
+			return BF_DEST_COLOR;
+		case OV_SrcColor:
+			return BF_SOURCE_COLOR;
+		case OV_InvDestColor:
+			return BF_INV_DEST_COLOR;
+		case OV_InvSrcColor:
+			return BF_INV_SOURCE_COLOR;
+		case OV_DestAlpha:
+			return BF_DEST_ALPHA;
+		case OV_SrcAlpha:
+			return BF_SOURCE_ALPHA;
+		case OV_InvDestAlpha:
+			return BF_INV_DEST_ALPHA;
+		case OV_InvSrcAlpha:
+			return BF_INV_SOURCE_ALPHA;
+		}
+
+		return BF_ONE;
+	}
+
+	BlendOperation BSLFXCompiler::parseBlendOp(BlendOpValue op)
+	{
+		switch (op)
+		{
+		case BOV_Add:
+			return BO_ADD;
+		case BOV_Max:
+			return BO_MAX;
+		case BOV_Min:
+			return BO_MIN;
+		case BOV_Subtract:
+			return BO_SUBTRACT;
+		case BOV_RevSubtract:
+			return BO_REVERSE_SUBTRACT;
+		}
+
+		return BO_ADD;
+	}
+
+	void BSLFXCompiler::parseParamType(ParamType type, bool& isObjType, UINT32& typeId)
+	{
+		struct ParamData
+		{
+			UINT32 type;
+			bool isObjType;
+		};
+
+		static bool initialized = false;
+		static ParamData lookup[PT_Count];
+
+		if (!initialized)
+		{
+			lookup[PT_Float] = { { GPDT_FLOAT1 }, false };
+			lookup[PT_Float2] = { { GPDT_FLOAT2 }, false };
+			lookup[PT_Float3] = { { GPDT_FLOAT3 }, false };
+			lookup[PT_Float4] = { { GPDT_FLOAT4 }, false };
+
+			lookup[PT_Int] = { { GPDT_INT1 }, false };
+			lookup[PT_Int2] = { { GPDT_INT2 }, false };
+			lookup[PT_Int3] = { { GPDT_INT3 }, false };
+			lookup[PT_Int4] = { { GPDT_INT4 }, false };
+
+			lookup[PT_Mat2x2] = { { GPDT_MATRIX_2X2 }, false };
+			lookup[PT_Mat2x3] = { { GPDT_MATRIX_2X3 }, false };
+			lookup[PT_Mat2x4] = { { GPDT_MATRIX_2X4 }, false };
+
+			lookup[PT_Mat3x2] = { { GPDT_MATRIX_3X2 }, false };
+			lookup[PT_Mat3x3] = { { GPDT_MATRIX_3X3 }, false };
+			lookup[PT_Mat3x4] = { { GPDT_MATRIX_3X4 }, false };
+
+			lookup[PT_Mat4x2] = { { GPDT_MATRIX_4X2 }, false };
+			lookup[PT_Mat4x3] = { { GPDT_MATRIX_4X3 }, false };
+			lookup[PT_Mat4x4] = { { GPDT_MATRIX_4X4 }, false };
+
+			lookup[PT_Sampler1D] = { { GPOT_SAMPLER1D }, true };
+			lookup[PT_Sampler2D] = { { GPOT_SAMPLER2D }, true };
+			lookup[PT_Sampler3D] = { { GPOT_SAMPLER3D }, true };
+			lookup[PT_SamplerCUBE] = { { GPOT_SAMPLERCUBE }, true };
+			lookup[PT_Sampler2DMS] = { { GPOT_SAMPLER2DMS }, true };
+
+			lookup[PT_Texture1D] = { { GPOT_TEXTURE1D }, true };
+			lookup[PT_Texture2D] = { { GPOT_TEXTURE2D }, true };
+			lookup[PT_Texture3D] = { { GPOT_TEXTURE3D }, true };
+			lookup[PT_TextureCUBE] = { { GPOT_TEXTURECUBE }, true };
+			lookup[PT_Texture2DMS] = { { GPOT_TEXTURE2DMS }, true };
+
+			lookup[PT_ByteBuffer] = { { GPOT_BYTE_BUFFER }, true };
+			lookup[PT_StructBuffer] = { { GPOT_STRUCTURED_BUFFER }, true };
+			lookup[PT_TypedBufferRW] = { { GPOT_RWTYPED_BUFFER }, true };
+			lookup[PT_ByteBufferRW] = { { GPOT_RWBYTE_BUFFER }, true };
+			lookup[PT_StructBufferRW] = { { GPOT_RWSTRUCTURED_BUFFER }, true };
+			lookup[PT_AppendBuffer] = { { GPOT_RWAPPEND_BUFFER }, true };
+			lookup[PT_ConsumeBuffer] = { { GPOT_RWCONSUME_BUFFER }, true };
+
+			initialized = true;
+		}
+
+		isObjType = lookup[type].isObjType;
+		typeId = lookup[type].type;
+	}
+
+	StencilOperation BSLFXCompiler::parseStencilOp(OpValue op)
+	{
+		switch (op)
+		{
+		case OV_Keep:
+			return SOP_KEEP;
+		case OV_Zero:
+			return SOP_ZERO;
+		case OV_Replace:
+			return SOP_REPLACE;
+		case OV_Incr:
+			return SOP_INCREMENT;
+		case OV_Decr:
+			return SOP_DECREMENT;
+		case OV_IncrWrap:
+			return SOP_INCREMENT_WRAP;
+		case OV_DecrWrap:
+			return SOP_DECREMENT_WRAP;
+		case OV_Invert:
+			return SOP_INVERT;
+		}
+
+		return SOP_KEEP;
+	}
+
+	CullingMode BSLFXCompiler::parseCullMode(CullModeValue cm)
+	{
+		switch (cm)
+		{
+		case CMV_None:
+			return CULL_NONE;
+		case CMV_CW:
+			return CULL_CLOCKWISE;
+		case CMV_CCW:
+			return CULL_COUNTERCLOCKWISE;
+		}
+
+		return CULL_COUNTERCLOCKWISE;
+	}
+
+	PolygonMode BSLFXCompiler::parseFillMode(FillModeValue fm)
+	{
+		if (fm == FMV_Wire)
+			return PM_WIREFRAME;
+
+		return PM_SOLID;
+	}
+
+	void BSLFXCompiler::parseStencilFront(DEPTH_STENCIL_STATE_DESC& desc, ASTFXNode* stencilOpNode)
+	{
+		if (stencilOpNode == nullptr || stencilOpNode->type != NT_StencilOp)
+			return;
+
+		for (int i = 0; i < stencilOpNode->options->count; i++)
+		{
+			NodeOption* option = &stencilOpNode->options->entries[i];
+
+			switch (option->type)
+			{
+			case OT_Fail:
+				desc.frontStencilFailOp = parseStencilOp((OpValue)option->value.intValue);
+				break;
+			case OT_ZFail:
+				desc.frontStencilZFailOp = parseStencilOp((OpValue)option->value.intValue);
+				break;
+			case OT_PassOp:
+				desc.frontStencilPassOp = parseStencilOp((OpValue)option->value.intValue);
+				break;
+			case OT_CompareFunc:
+				desc.frontStencilComparisonFunc = parseCompFunc((CompFuncValue)option->value.intValue);
+				break;
+			}
+		}
+	}
+
+	void BSLFXCompiler::parseStencilBack(DEPTH_STENCIL_STATE_DESC& desc, ASTFXNode* stencilOpNode)
+	{
+		if (stencilOpNode == nullptr || stencilOpNode->type != NT_StencilOp)
+			return;
+
+		for (int i = 0; i < stencilOpNode->options->count; i++)
+		{
+			NodeOption* option = &stencilOpNode->options->entries[i];
+
+			switch (option->type)
+			{
+			case OT_Fail:
+				desc.backStencilFailOp = parseStencilOp((OpValue)option->value.intValue);
+				break;
+			case OT_ZFail:
+				desc.backStencilZFailOp = parseStencilOp((OpValue)option->value.intValue);
+				break;
+			case OT_PassOp:
+				desc.backStencilPassOp = parseStencilOp((OpValue)option->value.intValue);
+				break;
+			case OT_CompareFunc:
+				desc.backStencilComparisonFunc = parseCompFunc((CompFuncValue)option->value.intValue);
+				break;
+			}
+		}
+	}
+
+	void BSLFXCompiler::parseAddrMode(SAMPLER_STATE_DESC& desc, ASTFXNode* addrModeNode)
+	{
+		if (addrModeNode == nullptr || addrModeNode->type != NT_AddrMode)
+			return;
+
+		for (int i = 0; i < addrModeNode->options->count; i++)
+		{
+			NodeOption* option = &addrModeNode->options->entries[i];
+
+			switch (option->type)
+			{
+			case OT_U:
+				desc.addressMode.u = parseAddrMode((AddrModeValue)option->value.intValue);
+				break;
+			case OT_V:
+				desc.addressMode.v = parseAddrMode((AddrModeValue)option->value.intValue);
+				break;
+			case OT_W:
+				desc.addressMode.w = parseAddrMode((AddrModeValue)option->value.intValue);
+				break;
+			}
+		}
+	}
+
+	void BSLFXCompiler::parseColorBlendDef(RENDER_TARGET_BLEND_STATE_DESC& desc, ASTFXNode* blendDefNode)
+	{
+		if (blendDefNode == nullptr || blendDefNode->type != NT_BlendDef)
+			return;
+
+		for (int i = 0; i < blendDefNode->options->count; i++)
+		{
+			NodeOption* option = &blendDefNode->options->entries[i];
+
+			switch (option->type)
+			{
+			case OT_Source:
+				desc.srcBlend = parseBlendFactor((OpValue)option->value.intValue);
+				break;
+			case OT_Dest:
+				desc.dstBlend = parseBlendFactor((OpValue)option->value.intValue);
+				break;
+			case OT_Op:
+				desc.blendOp = parseBlendOp((BlendOpValue)option->value.intValue);
+				break;
+			}
+		}
+	}
+
+	void BSLFXCompiler::parseAlphaBlendDef(RENDER_TARGET_BLEND_STATE_DESC& desc, ASTFXNode* blendDefNode)
+	{
+		if (blendDefNode == nullptr || blendDefNode->type != NT_BlendDef)
+			return;
+
+		for (int i = 0; i < blendDefNode->options->count; i++)
+		{
+			NodeOption* option = &blendDefNode->options->entries[i];
+
+			switch (option->type)
+			{
+			case OT_Source:
+				desc.srcBlendAlpha = parseBlendFactor((OpValue)option->value.intValue);
+				break;
+			case OT_Dest:
+				desc.dstBlendAlpha = parseBlendFactor((OpValue)option->value.intValue);
+				break;
+			case OT_Op:
+				desc.blendOpAlpha = parseBlendOp((BlendOpValue)option->value.intValue);
+				break;
+			}
+		}
+	}
+
+	void BSLFXCompiler::parseRenderTargetBlendState(BLEND_STATE_DESC& desc, ASTFXNode* targetNode)
+	{
+		if (targetNode == nullptr || targetNode->type != NT_Target)
+			return;
+
+		UINT32 index = 0;
+
+		for (int i = 0; i < targetNode->options->count; i++)
+		{
+			NodeOption* option = &targetNode->options->entries[i];
+
+			switch (option->type)
+			{
+			case OT_Index:
+				index = option->value.intValue;
+				break;
+			}
+		}
+
+		if (index >= BS_MAX_MULTIPLE_RENDER_TARGETS)
+			return;
+
+		RENDER_TARGET_BLEND_STATE_DESC& rtDesc = desc.renderTargetDesc[index];
+		for (int i = 0; i < targetNode->options->count; i++)
+		{
+			NodeOption* option = &targetNode->options->entries[i];
+
+			switch (option->type)
+			{
+			case OT_Blend:
+				rtDesc.blendEnable = option->value.intValue > 0;
+				break;
+			case OT_Color:
+				parseColorBlendDef(rtDesc, option->value.nodePtr);
+				break;
+			case OT_Alpha:
+				parseAlphaBlendDef(rtDesc, option->value.nodePtr);
+				break;
+			case OT_WriteMask:
+				rtDesc.renderTargetWriteMask = option->value.intValue;
+				break;
+			}
+		}
+	}
+
+	bool BSLFXCompiler::parseBlendState(BLEND_STATE_DESC& desc, ASTFXNode* passNode)
+	{
+		if (passNode == nullptr || (passNode->type != NT_Pass && passNode->type != NT_Technique))
+			return false;
+
+		bool default = true;
+
+		for (int i = 0; i < passNode->options->count; i++)
+		{
+			NodeOption* option = &passNode->options->entries[i];
+
+			switch (option->type)
+			{
+			case OT_AlphaToCoverage:
+				desc.alphaToCoverageEnable = option->value.intValue > 0;
+				default = false;
+				break;
+			case OT_IndependantBlend:
+				desc.independantBlendEnable = option->value.intValue > 0;
+				default = false;
+				break;
+			case OT_Target:
+				parseRenderTargetBlendState(desc, option->value.nodePtr);
+				default = false;
+				break;
+			}
+		}
+
+		return !default;
+	}
+
+	bool BSLFXCompiler::parseRasterizerState(RASTERIZER_STATE_DESC& desc, ASTFXNode* passNode)
+	{
+		if (passNode == nullptr || (passNode->type != NT_Pass && passNode->type != NT_Technique))
+			return false;
+
+		bool default = true;
+
+		for (int i = 0; i < passNode->options->count; i++)
+		{
+			NodeOption* option = &passNode->options->entries[i];
+
+			switch (option->type)
+			{
+			case OT_FillMode:
+				desc.polygonMode = parseFillMode((FillModeValue)option->value.intValue);
+				default = false;
+				break;
+			case OT_CullMode:
+				desc.cullMode = parseCullMode((CullModeValue)option->value.intValue);
+				default = false;
+				break;
+			case OT_DepthBias:
+				desc.depthBias = option->value.floatValue;
+				default = false;
+				break;
+			case OT_SDepthBias:
+				desc.slopeScaledDepthBias = option->value.floatValue;
+				default = false;
+				break;
+			case OT_DepthClip:
+				desc.depthClipEnable = option->value.intValue > 0;
+				default = false;
+				break;
+			case OT_Scissor:
+				desc.scissorEnable = option->value.intValue > 0;
+				default = false;
+				break;
+			case OT_Multisample:
+				desc.multisampleEnable = option->value.intValue > 0;
+				default = false;
+				break;
+			case OT_AALine:
+				desc.antialiasedLineEnable = option->value.intValue > 0;
+				default = false;
+				break;
+			}
+		}
+
+		return !default;
+	}
+
+	bool BSLFXCompiler::parseDepthStencilState(DEPTH_STENCIL_STATE_DESC& desc, ASTFXNode* passNode)
+	{
+		if (passNode == nullptr || (passNode->type != NT_Pass && passNode->type != NT_Technique))
+			return false;
+
+		bool default = true;
+
+		for (int i = 0; i < passNode->options->count; i++)
+		{
+			NodeOption* option = &passNode->options->entries[i];
+
+			switch (option->type)
+			{
+			case OT_DepthRead:
+				desc.depthReadEnable = option->value.intValue > 0;
+				default = false;
+				break;
+			case OT_DepthWrite:
+				desc.depthWriteEnable = option->value.intValue > 0;
+				default = false;
+				break;
+			case OT_CompareFunc:
+				desc.depthComparisonFunc = parseCompFunc((CompFuncValue)option->value.intValue);
+				default = false;
+				break;
+			case OT_Stencil:
+				desc.stencilEnable = option->value.intValue > 0;
+				default = false;
+				break;
+			case OT_StencilReadMask:
+				desc.stencilReadMask = (UINT8)option->value.intValue;
+				default = false;
+				break;
+			case OT_StencilWriteMask:
+				desc.stencilWriteMask = (UINT8)option->value.intValue;
+				default = false;
+				break;
+			case OT_StencilOpFront:
+				parseStencilFront(desc, option->value.nodePtr);
+				default = false;
+				break;
+			case OT_StencilOpBack:
+				parseStencilBack(desc, option->value.nodePtr);
+				default = false;
+				break;
+			}
+		}
+
+		return !default;
+	}
+
+	SamplerStatePtr BSLFXCompiler::parseSamplerState(ASTFXNode* samplerStateNode)
+	{
+		if (samplerStateNode == nullptr || samplerStateNode->type != NT_SamplerState)
+			return nullptr;
+
+		SAMPLER_STATE_DESC desc;
+		bool default = true;
+
+		for (int i = 0; i < samplerStateNode->options->count; i++)
+		{
+			NodeOption* option = &samplerStateNode->options->entries[i];
+
+			switch (option->type)
+			{
+			case OT_AddrMode:
+				parseAddrMode(desc, option->value.nodePtr);
+				default = false;
+				break;
+			case OT_MinFilter:
+				desc.minFilter = (FilterOptions)parseFilterMode((FilterValue)option->value.intValue);
+				default = false;
+				break;
+			case OT_MagFilter:
+				desc.magFilter = (FilterOptions)parseFilterMode((FilterValue)option->value.intValue);
+				default = false;
+				break;
+			case OT_MipFilter:
+				desc.mipFilter = (FilterOptions)parseFilterMode((FilterValue)option->value.intValue);
+				default = false;
+				break;
+			case OT_MaxAniso:
+				desc.maxAniso = option->value.intValue;
+				default = false;
+				break;
+			case OT_MipBias:
+				desc.mipmapBias = option->value.floatValue;
+				default = false;
+				break;
+			case OT_MipMin:
+				desc.mipMin = option->value.floatValue;
+				default = false;
+				break;
+			case OT_MipMax:
+				desc.mipMax = option->value.floatValue;
+				default = false;
+				break;
+			case OT_BorderColor:
+				desc.borderColor = Color(option->value.matrixValue[0], option->value.matrixValue[1],
+					option->value.matrixValue[2], option->value.matrixValue[3]);
+				default = false;
+				break;
+			case OT_CompareFunc:
+				desc.comparisonFunc = parseCompFunc((CompFuncValue)option->value.intValue);
+				default = false;
+				break;
+			}
+		}
+
+		if (default)
+			return nullptr;
+
+		return SamplerState::create(desc);
+	}
+
+	void BSLFXCompiler::parseCodeBlock(ASTFXNode* codeNode, const Vector<String>& codeBlocks, PassData& passData)
+	{
+		if (codeNode == nullptr || (codeNode->type != NT_CodeCommon && codeNode->type != NT_CodeVertex && 
+			codeNode->type != NT_CodeFragment && codeNode->type != NT_CodeGeometry && codeNode->type != NT_CodeHull &&
+			codeNode->type != NT_CodeDomain && codeNode->type != NT_CodeCompute))
+		{
+			return;
+		}
+
+		UINT32 index = (UINT32)-1;
+		for (int j = 0; j < codeNode->options->count; j++)
+		{
+			if (codeNode->options->entries[j].type == OT_Index)
+				index = codeNode->options->entries[j].value.intValue;
+		}
+
+		if (index != (UINT32)-1 && index < (UINT32)codeBlocks.size())
+		{
+			switch (codeNode->type)
+			{
+			case NT_CodeVertex:
+				passData.vertexCode += codeBlocks[index];
+				break;
+			case NT_CodeFragment:
+				passData.fragmentCode += codeBlocks[index];
+				break;
+			case NT_CodeGeometry:
+				passData.geometryCode += codeBlocks[index];
+				break;
+			case NT_CodeHull:
+				passData.hullCode += codeBlocks[index];
+				break;
+			case NT_CodeDomain:
+				passData.domainCode += codeBlocks[index];
+				break;
+			case NT_CodeCompute:
+				passData.computeCode += codeBlocks[index];
+				break;
+			case NT_CodeCommon:
+				passData.commonCode += codeBlocks[index];
+				break;
+			}
+		}
+	}
+
+	void BSLFXCompiler::parsePass(ASTFXNode* passNode, const Vector<String>& codeBlocks, PassData& passData)
+	{
+		if (passNode == nullptr || passNode->type != NT_Pass)
+			return;
+
+		passData.blendIsDefault &= !parseBlendState(passData.blendDesc, passNode);
+		passData.rasterizerIsDefault &= !parseRasterizerState(passData.rasterizerDesc, passNode);
+		passData.depthStencilIsDefault &= !parseDepthStencilState(passData.depthStencilDesc, passNode);
+
+		for (int i = 0; i < passNode->options->count; i++)
+		{
+			NodeOption* option = &passNode->options->entries[i];
+
+			switch (option->type)
+			{
+			case OT_StencilRef:
+				passData.stencilRefValue = option->value.intValue;
+				break;
+			case OT_Code:
+				parseCodeBlock(option->value.nodePtr, codeBlocks, passData);
+				break;
+			}
+		}
+	}
+
+	void BSLFXCompiler::parseTechnique(ASTFXNode* techniqueNode, const Vector<String>& codeBlocks, TechniqueData& techniqueData)
+	{
+		if (techniqueNode == nullptr || techniqueNode->type != NT_Technique)
+			return;
+
+		UINT32 nextPassIdx = 0;
+		// Go in reverse because options are added in reverse order during parsing
+		for (int i = techniqueNode->options->count - 1; i >= 0; i--)
+		{
+			NodeOption* option = &techniqueNode->options->entries[i];
+
+			switch (option->type)
+			{
+			case OT_Pass:
+			{
+				UINT32 passIdx = nextPassIdx;
+
+				ASTFXNode* passNode = option->value.nodePtr;
+				for (int j = 0; j < passNode->options->count; j++)
+				{
+					NodeOption* passOption = &passNode->options->entries[j];
+
+					switch (passOption->type)
+					{
+					case OT_Index:
+						passIdx = passOption->value.intValue;
+						break;
+					}
+				}
+
+				PassData* passData = nullptr;
+				for (auto& entry : techniqueData.passes)
+				{
+					if (entry.seqIdx == passIdx)
+						passData = &entry;
+				}
+
+				if (passData == nullptr)
+				{
+					techniqueData.passes.push_back(PassData());
+					passData = &techniqueData.passes.back();
+
+					passData->seqIdx = passIdx;
+				}
+
+				nextPassIdx = std::max(nextPassIdx, passIdx) + 1;
+
+				passData->blendIsDefault &= !parseBlendState(passData->blendDesc, techniqueNode);
+				passData->rasterizerIsDefault &= !parseRasterizerState(passData->rasterizerDesc, techniqueNode);
+				passData->depthStencilIsDefault &= !parseDepthStencilState(passData->depthStencilDesc, techniqueNode);
+
+				passData->vertexCode = techniqueData.commonPassData.vertexCode + passData->vertexCode;
+				passData->fragmentCode = techniqueData.commonPassData.fragmentCode + passData->fragmentCode;
+				passData->geometryCode = techniqueData.commonPassData.geometryCode + passData->geometryCode;
+				passData->hullCode = techniqueData.commonPassData.hullCode + passData->hullCode;
+				passData->domainCode = techniqueData.commonPassData.domainCode + passData->domainCode;
+				passData->commonCode = techniqueData.commonPassData.commonCode + passData->commonCode;
+				
+				parsePass(passNode, codeBlocks, *passData);
+			}
+				break;
+			case OT_Renderer:
+				techniqueData.renderer = parseRenderer(removeQuotes(option->value.strValue));
+				break;
+			case OT_Language:
+				parseLanguage(removeQuotes(option->value.strValue), techniqueData.renderAPI, techniqueData.language);
+				break;
+			case OT_Code:
+				parseCodeBlock(option->value.nodePtr, codeBlocks, techniqueData.commonPassData);
+				break;
+			}
+		}
+	}
+
+	void BSLFXCompiler::parseParameters(SHADER_DESC& desc, ASTFXNode* parametersNode)
+	{
+		if (parametersNode == nullptr || parametersNode->type != NT_Parameters)
+			return;
+
+		for (int i = 0; i < parametersNode->options->count; i++)
+		{
+			NodeOption* option = &parametersNode->options->entries[i];
+
+			if (option->type != OT_Parameter)
+				continue;
+
+			ASTFXNode* parameter = option->value.nodePtr;
+
+			String name;
+			String alias;
+
+			UINT32 typeId = 0;
+			bool isObjType = false;
+			StringID semantic;
+			SamplerStatePtr samplerState = nullptr;
+			float defaultValue[16];
+			HTexture defaultTexture;
+			bool hasDefaultValue = false;
+			for (int j = 0; j < parameter->options->count; j++)
+			{
+				NodeOption* paramOption = &parameter->options->entries[j];
+
+				switch (paramOption->type)
+				{
+				case OT_Identifier:
+					name = paramOption->value.strValue;
+					break;
+				case OT_Alias:
+					alias = removeQuotes(paramOption->value.strValue);
+					break;
+				case OT_ParamType:
+					parseParamType((ParamType)paramOption->value.intValue, isObjType, typeId);
+					break;
+				case OT_ParamValue:
+					memcpy(defaultValue, paramOption->value.matrixValue, sizeof(defaultValue));
+					hasDefaultValue = true;
+					break;
+				case OT_ParamStrValue:
+				{
+					String defaultTextureName = removeQuotes(paramOption->value.strValue);
+					defaultTexture = getBuiltinTexture(defaultTextureName);
+					hasDefaultValue = true;
+				}
+					break;
+				case OT_Auto:
+					semantic = removeQuotes(paramOption->value.strValue);
+					break;
+				case OT_SamplerState:
+					samplerState = parseSamplerState(paramOption->value.nodePtr);
+					break;
+				}
+			}
+
+			if (name.empty())
+				continue;
+
+			auto addParameter = [&](const String& paramName, const String& gpuVarName)
+			{
+				if (isObjType)
+				{
+					GpuParamObjectType objType = (GpuParamObjectType)typeId;
+
+					if (Shader::isSampler(objType))
+					{
+						if(hasDefaultValue)
+							desc.addParameter(paramName, gpuVarName, objType, samplerState, semantic);
+						else
+							desc.addParameter(paramName, gpuVarName, objType, semantic);
+					}
+					else if(Shader::isTexture(objType))
+					{
+						if(hasDefaultValue)
+							desc.addParameter(paramName, gpuVarName, objType, defaultTexture, semantic);
+						else
+							desc.addParameter(paramName, gpuVarName, objType, semantic);
+					}
+					else
+						desc.addParameter(paramName, gpuVarName, objType, semantic);
+				}
+				else
+				{
+					if (hasDefaultValue)
+						desc.addParameter(paramName, gpuVarName, (GpuParamDataType)typeId, semantic, 1, 0, (UINT8*)defaultValue);
+					else
+						desc.addParameter(paramName, gpuVarName, (GpuParamDataType)typeId, semantic);
+				}
+			};
+
+			addParameter(name, name);
+
+			if (!alias.empty())
+				addParameter(name, alias);
+		}
+	}
+
+	void BSLFXCompiler::parseBlocks(SHADER_DESC& desc, ASTFXNode* blocksNode)
+	{
+		if (blocksNode == nullptr || blocksNode->type != NT_Blocks)
+			return;
+
+		for (int i = 0; i < blocksNode->options->count; i++)
+		{
+			NodeOption* option = &blocksNode->options->entries[i];
+
+			if (option->type != OT_Block)
+				continue;
+
+			ASTFXNode* parameter = option->value.nodePtr;
+
+			String name;
+			bool shared = false;
+			GpuParamBlockUsage usage = GPBU_STATIC;
+			StringID semantic;
+
+			for (int j = 0; j < parameter->options->count; j++)
+			{
+				NodeOption* paramOption = &parameter->options->entries[j];
+
+				switch (paramOption->type)
+				{
+				case OT_Identifier:
+					name = paramOption->value.strValue;
+					break;
+				case OT_Shared:
+					shared = paramOption->value.intValue > 0;
+					break;
+				case OT_Usage:
+					usage = parseBlockUsage((BufferUsageValue)paramOption->value.intValue);
+					break;
+				case OT_Auto:
+					semantic = removeQuotes(paramOption->value.strValue);
+					break;
+				}
+			}
+
+			if (name.empty())
+				continue;
+
+			desc.setParamBlockAttribs(name, shared, usage, semantic);
+		}
+	}
+
+	BSLFXCompileResult BSLFXCompiler::parseShader(const String& name, ParseState* parseState, Vector<String>& codeBlocks)
+	{
+		BSLFXCompileResult output;
+
+		if (parseState->rootNode == nullptr || parseState->rootNode->type != NT_Shader)
+		{
+			output.errorMessage = "Root not is null or not a shader.";
+			return output;
+		}
+
+		SHADER_DESC shaderDesc;
+		Vector<pair<ASTFXNode*, TechniqueData>> techniqueData;
+
+		// Go in reverse because options are added in reverse order during parsing
+		for (int i = parseState->rootNode->options->count - 1; i >= 0; i--)
+		{
+			NodeOption* option = &parseState->rootNode->options->entries[i];
+
+			switch (option->type)
+			{
+			case OT_Separable:
+				shaderDesc.separablePasses = option->value.intValue > 1;
+				break;
+			case OT_Queue:
+				shaderDesc.queuePriority = option->value.intValue;
+				break;
+			case OT_Priority:
+				shaderDesc.queuePriority = option->value.intValue;
+				break;
+			case OT_Transparent:
+				shaderDesc.flags |= (UINT32)ShaderFlags::Transparent;
+				break;
+			case OT_Technique:
+			{
+				auto iterFind = std::find_if(techniqueData.begin(), techniqueData.end(), 
+					[&] (auto x)
+				{
+					return doTechniquesMatch(x.first, option->value.nodePtr);
+				});
+
+				TechniqueData* data = nullptr;
+				if (iterFind != techniqueData.end())
+					data = &iterFind->second;
+				else
+				{
+					techniqueData.push_back(std::make_pair(option->value.nodePtr, TechniqueData()));
+					data = &techniqueData.back().second;
+				}
+
+				parseTechnique(option->value.nodePtr, codeBlocks, *data);
+				break;
+			}
+			case OT_Parameters:
+				parseParameters(shaderDesc, option->value.nodePtr);
+				break;
+			case OT_Blocks:
+				parseBlocks(shaderDesc, option->value.nodePtr);
+				break;
+			}
+		}
+
+		Vector<TechniquePtr> techniques;
+		for(auto& entry : techniqueData)
+		{
+			const TechniqueData& techniqueData = entry.second;
+
+			Map<UINT32, PassPtr, std::greater<UINT32>> passes;
+			for (auto& passData : entry.second.passes)
+			{
+				PASS_DESC passDesc;
+
+				if (!passData.blendIsDefault)
+					passDesc.blendState = BlendState::create(passData.blendDesc);
+
+				if (!passData.rasterizerIsDefault)
+					passDesc.rasterizerState = RasterizerState::create(passData.rasterizerDesc);
+
+				if (!passData.depthStencilIsDefault)
+					passDesc.depthStencilState = DepthStencilState::create(passData.depthStencilDesc);
+
+				if (!passData.vertexCode.empty())
+				{
+					passDesc.vertexProgram = GpuProgram::create(passData.commonCode + passData.vertexCode, "main", 
+						techniqueData.language, GPT_VERTEX_PROGRAM, getProfile(techniqueData.renderAPI, GPT_VERTEX_PROGRAM));
+				}
+
+				if (!passData.fragmentCode.empty())
+				{
+					passDesc.fragmentProgram = GpuProgram::create(passData.commonCode + passData.fragmentCode, "main", 
+						techniqueData.language, GPT_FRAGMENT_PROGRAM, getProfile(techniqueData.renderAPI, GPT_FRAGMENT_PROGRAM));
+				}
+
+				if (!passData.geometryCode.empty())
+				{
+					passDesc.geometryProgram = GpuProgram::create(passData.commonCode + passData.geometryCode, "main", 
+						techniqueData.language, GPT_GEOMETRY_PROGRAM, getProfile(techniqueData.renderAPI, GPT_GEOMETRY_PROGRAM));
+				}
+
+				if (!passData.hullCode.empty())
+				{
+					passDesc.hullProgram = GpuProgram::create(passData.commonCode + passData.hullCode, "main", 
+						techniqueData.language, GPT_HULL_PROGRAM, getProfile(techniqueData.renderAPI, GPT_HULL_PROGRAM));
+				}
+
+				if (!passData.domainCode.empty())
+				{
+					passDesc.domainProgram = GpuProgram::create(passData.commonCode + passData.domainCode, "main", 
+						techniqueData.language, GPT_DOMAIN_PROGRAM, getProfile(techniqueData.renderAPI, GPT_DOMAIN_PROGRAM));
+				}
+
+				if (!passData.computeCode.empty())
+				{
+					passDesc.computeProgram = GpuProgram::create(passData.commonCode + passData.computeCode, "main", 
+						techniqueData.language, GPT_COMPUTE_PROGRAM, getProfile(techniqueData.renderAPI, GPT_COMPUTE_PROGRAM));
+				}
+
+				passDesc.stencilRefValue = passData.stencilRefValue;
+
+				PassPtr pass = Pass::create(passDesc);
+				if (pass != nullptr)
+					passes[passData.seqIdx] = pass;
+			}
+
+			Vector<PassPtr> orderedPasses;
+			for (auto& KVP : passes)
+				orderedPasses.push_back(KVP.second);
+
+			if (orderedPasses.size() > 0)
+			{
+				TechniquePtr technique = Technique::create(techniqueData.renderAPI, techniqueData.renderer, orderedPasses);
+				techniques.push_back(technique);
+			}
+		}
+
+		Vector<String> includes;
+		IncludeLink* includeLink = parseState->includes;
+		while(includeLink != nullptr)
+		{
+			String includeFilename = includeLink->data->filename;
+
+			auto iterFind = std::find(includes.begin(), includes.end(), includeFilename);
+			if (iterFind == includes.end())
+				includes.push_back(includeFilename);
+
+			includeLink = includeLink->next;
+		}
+
+		parseStateDelete(parseState);
+
+		output.shader = Shader::_createPtr(name, shaderDesc, techniques);
+		output.shader->setIncludeFiles(includes);
+
+		return output;
+	}
+
+	String BSLFXCompiler::removeQuotes(const char* input)
+	{
+		UINT32 len = (UINT32)strlen(input);
+		String output(len - 2, ' ');
+
+		for (UINT32 i = 0; i < (len - 2); i++)
+			output[i] = input[i + 1];
+
+		return output;
+	}
+
+	GpuProgramProfile BSLFXCompiler::getProfile(const StringID& renderAPI, GpuProgramType type)
+	{
+		StringID target = renderAPI;
+		if (target == RenderAPIAny)
+			target = RenderAPICore::instance().getName();
+
+		if (target == RenderAPIDX11 || target == RenderAPIOpenGL)
+		{
+			switch (type)
+			{
+			case GPT_VERTEX_PROGRAM:
+				return GPP_VS_5_0;
+			case GPT_FRAGMENT_PROGRAM:
+				return GPP_FS_5_0;
+			case GPT_GEOMETRY_PROGRAM:
+				return GPP_GS_5_0;
+			case GPT_HULL_PROGRAM:
+				return GPP_HS_5_0;
+			case GPT_DOMAIN_PROGRAM:
+				return GPP_DS_5_0;
+			case GPT_COMPUTE_PROGRAM:
+				return GPP_CS_5_0;
+			}
+		}
+		else if (target == RenderAPIDX9)
+		{
+			switch (type)
+			{
+			case GPT_VERTEX_PROGRAM:
+				return GPP_VS_3_0;
+			case GPT_FRAGMENT_PROGRAM:
+				return GPP_FS_3_0;
+			}
+		}
+
+		return GPP_NONE;
+	}
+
+	HTexture BSLFXCompiler::getBuiltinTexture(const String& name)
+	{
+		if (StringUtil::compare(name, String("white"), false) == 0)
+			return BuiltinResources::getTexture(BuiltinTexture::White);
+		else if (StringUtil::compare(name, String("black"), false) == 0)
+			return BuiltinResources::getTexture(BuiltinTexture::Black);
+		else if (StringUtil::compare(name, String("normal"), false) == 0)
+			return BuiltinResources::getTexture(BuiltinTexture::Normal);
+
+		return HTexture();
+	}
 }
 }

+ 2 - 1
Source/BansheeSL/Source/BsSLImporter.cpp

@@ -37,7 +37,8 @@ namespace BansheeEngine
 		DataStreamPtr stream = FileSystem::openFile(filePath);
 		DataStreamPtr stream = FileSystem::openFile(filePath);
 		String source = stream->getAsString();
 		String source = stream->getAsString();
 
 
-		BSLFXCompileResult result = BSLFXCompiler::compile(source);
+		SPtr<const ShaderImportOptions> io = std::static_pointer_cast<const ShaderImportOptions>(importOptions);
+		BSLFXCompileResult result = BSLFXCompiler::compile(source, io->getDefines());
 
 
 		if (result.shader != nullptr)
 		if (result.shader != nullptr)
 			result.shader->setName(filePath.getWFilename(false));
 			result.shader->setName(filePath.getWFilename(false));

Unele fișiere nu au fost afișate deoarece prea multe fișiere au fost modificate în acest diff