OPTIONS
{
	DEBUG_SCANNER = false;
	DEBUG_PARSER = false;
	CASE_SENSITIVE = true;
	USE_EXCEPTIONS = true;
	DEFAULT_LOOKAHEAD = 1000000000;
	SHARP_LINES = false;
	TOKENS_SPAN_EOF = false;
	COUNT_COLUMNS = false;
	PROFILING_FILE = "";
//	STRING_CLASS = std::string;
	NAMESPACE_NAME = "vs20";
	SRC_EXTENSION = "cpp";
	HDR_EXTENSION = "hpp";
}

{ 
#pragma warning(disable : 4290)
#pragma warning(disable : 4786)

#undef TRUE
#undef FALSE
}

TOKEN vs20_token
{
public:
	int integer;
	double real;
}

{
#include "Error.hpp"

#pragma warning(disable : 4290)
#pragma warning(disable : 4786)
}

SCANNER vs20_scanner
{
	<START> SKIP
	{
		<BLANK: " " | "\t" | "\v" | "\f">
		<COMMENT1: "//" (~['\n','\r'])* >
		<COMMENT2: ";" (~['\n','\r'])* >
	}
	
	<START> MORE
	{
		<LONG_COMMENT1: "/*" > {pushState(LONG_COMMENT);}
	}

	<LONG_COMMENT> MORE
	{
		<LONG_COMMENT2: "\n"/* | "\r" | "\n\r" | "\r\n"*/>
		<LONG_COMMENT3: ~['*','\n','\r']*>
		<LONG_COMMENT4: ['*']+~['/','\n']>
		<LONG_COMMENT5: ['*']+"\n">
	}

	<LONG_COMMENT> SKIP
	{
		<LONG_COMMENT: ['*']+"/" > {popState();}
	}
	
	<START> TOKEN
	{
		<EOL: "\n" | "\r" | "\n\r" | "\r\n">
	}

	<START> KEYWORD
	{
		<X: "x" | "r">
		<Y: "y" | "g">
		<Z: "z" | "b">
		<W: "w" | "a">
	}

	<START> KEYWORD
	{
		<COMMA: ",">
		<DOT: ".">
		<MINUS: "-">
		
		<TRUE: "True">		{token->integer = 1;}
		<FALSE: "False">	{token->integer = 0;}
	}

	<START> TOKEN
	{
		<#DIGIT: ['0'-'9']>
		<#DIGITS: <DIGIT>+>
		<#SIGN: ['+','-']>
		<#EXPONENT: ['e', 'E']>
		<INTEGER: <SIGN>? <DIGITS>>
		<REAL: (<SIGN>? <DIGITS>? ("." <DIGITS>) |
		        (("." <DIGITS>)? <EXPONENT> <SIGN>? <DIGITS>)) "f"?>
	}

	<START> KEYWORD
	{
		<VS_2_0: "vs_2_0">
		
		<DCL_POSITION: "dcl_position"<DIGITS>?>
		{
			token->integer = atoi(token->image().c_str() + 12);
			if(token->integer >= 2) throw swShader::Error("Syntax swShader::Error: dcl_position%d index out of range", token->integer);
		}
		
		<DCL_BLENDWEIGHT: "dcl_blendweight"<DIGITS>?>
		{
			token->integer = atoi(token->image().c_str() + 15);
			if(token->integer >= 1) throw swShader::Error("Syntax swShader::Error: dcl_blendweight%d index out of range", token->integer);
		}
		
		<DCL_BLENDINDICES: "dcl_blendindices"<DIGITS>?>
		{
			token->integer = atoi(token->image().c_str() + 16);
			if(token->integer >= 1) throw swShader::Error("Syntax swShader::Error: dcl_blendindices%d index out of range", token->integer);
		}
		
		<DCL_NORMAL: "dcl_normal"<DIGITS>?>
		{
			token->integer = atoi(token->image().c_str() + 10);
			if(token->integer >= 2) throw swShader::Error("Syntax swShader::Error: dcl_normal%d index out of range", token->integer);
		}
		
		<DCL_PSIZE: "dcl_psize"<DIGITS>?>
		{
			token->integer = atoi(token->image().c_str() + 9);
			if(token->integer >= 1) throw swShader::Error("Syntax swShader::Error: dcl_psize%d index out of range", token->integer);
		}
		
		<DCL_TEXCOORD: "dcl_texcoord"<DIGITS>?>
		{
			token->integer = atoi(token->image().c_str() + 12);
			if(token->integer >= 8) throw swShader::Error("Syntax swShader::Error: dcl_texcoord%d index out of range", token->integer);
		}
		
		<DCL_TANGENT: "dcl_tangent"<DIGITS>?>
		{
			token->integer = atoi(token->image().c_str() + 11);
			if(token->integer >= 1) throw swShader::Error("Syntax swShader::Error: dcl_tangent%d index out of range", token->integer);
		}
		
		<DCL_BINORMAL: "dcl_binormal"<DIGITS>?>
		{
			token->integer = atoi(token->image().c_str() + 12);
			if(token->integer >= 1) throw swShader::Error("Syntax swShader::Error: dcl_binormal%d index out of range", token->integer);
		}
		
		<DCL_TESSFACTOR: "dcl_tessfactor"<DIGITS>?>
		{
			token->integer = atoi(token->image().c_str() + 14);
			if(token->integer >= 1) throw swShader::Error("Syntax swShader::Error: dcl_tessfactor%d index out of range", token->integer);
		}
		
		<DCL_POSITIONT: "dcl_positiont"<DIGITS>?>
		{
			token->integer = atoi(token->image().c_str() + 13);
			if(token->integer >= 1) throw swShader::Error("Syntax swShader::Error: dcl_positiont%d index out of range", token->integer);
		}
		
		<DCL_COLOR: "dcl_color"<DIGITS>?>
		{
			token->integer = atoi(token->image().c_str() + 9);
			if(token->integer >= 2) throw swShader::Error("Syntax swShader::Error: dcl_color%d index out of range", token->integer);
		}
		
		<DCL_FOG: "dcl_fog"<DIGITS>?>
		{
			token->integer = atoi(token->image().c_str() + 7);
			if(token->integer >= 1) throw swShader::Error("Syntax swShader::Error: dcl_fog%d index out of range", token->integer);
		}
		
		<DCL_DEPTH: "dcl_depth"<DIGITS>?>
		{
			token->integer = atoi(token->image().c_str() + 9);
			if(token->integer >= 16) throw swShader::Error("Syntax swShader::Error: dcl_depth%d index out of range", token->integer);
		}
		
		<DCL_SAMPLE: "dcl_sample"<DIGITS>?>
		{
			token->integer = atoi(token->image().c_str() + 10);
			if(token->integer >= 1) throw swShader::Error("Syntax swShader::Error: dcl_sample%d index out of range", token->integer);
		}
		
		<DEF: "def">
		<DEFB: "defb">
		<DEFI: "defi">
	
		<ABS: "abs">
		<ADD: "add">
		<CALL: "call">
		<CALLNZ: "callnz">
		<CRS: "crs">
		<DP3: "dp3">
		<DP4: "dp4">
		<DST: "dst">
		<ELSE: "else">
		<ENDIF: "endif">
		<ENDLOOP: "endloop">
		<ENDREP: "endrep">
		<EXP: "exp">
		<EXPP: "expp">
		<FRC: "frc">
		<IF: "if">
		<LABEL: "label">
		<LIT: "lit">
		<LOG: "log">
		<LOGP: "logp">
		<LOOP: "loop">
		<LRP: "lrp">
		<M3X2: "m3x2">
		<M3X3: "m3x3">
		<M3X4: "m3x4">
		<M4X3: "m4x3">
		<M4X4: "m4x4">
		<MAD: "mad">
		<MAX: "max">
		<MIN: "min">
		<MOV: "mov">
		<MOVA: "mova">
		<MUL: "mul">
		<NOP: "nop">
		<NRM: "nrm">
		<POW: "pow">
		<RCP: "rcp">
		<REP: "rep">
		<RET: "ret">
		<RSQ: "rsq">
		<SGE: "sge">
		<SGN: "sgn">
		<SINCOS: "sincos">
		<SLT: "slt">
		
		<_SAT: "_sat">
	}

	<START> KEYWORD
	{
		<V: "v"<DIGITS>>
		{
			token->integer = atoi(token->image().c_str() + 1);
			if(token->integer >= 16) throw swShader::Error("Syntax swShader::Error: v%d index out of range", token->integer);
		}
		
		<R: "r"<DIGITS>>
		{
			token->integer = atoi(token->image().c_str() + 1);
			if(token->integer >= 12) throw swShader::Error("Syntax swShader::Error: r%d index out of range", token->integer);
		}
		
		<C: "c"<DIGITS>>
		{
			token->integer = atoi(token->image().c_str() + 1);
			if(token->integer >= 256) throw swShader::Error("Syntax swShader::Error: c%d index out of range", token->integer);
		}
		
		<I: "i"<DIGITS>>
		{
			token->integer = atoi(token->image().c_str() + 1);
			if(token->integer >= 16) throw swShader::Error("Syntax swShader::Error: i%d index out of range", token->integer);
		}
		
		<B: "b"<DIGITS>>
		{
			token->integer = atoi(token->image().c_str() + 1);
			if(token->integer >= 16) throw swShader::Error("Syntax swShader::Error: b%d index out of range", token->integer);
		}
		
		<A0: "a0">
		<AL: "aL">
		
		<O_D: "oD"<DIGITS>>
		{
			token->integer = atoi(token->image().c_str() + 2);
			if(token->integer >= 2) throw swShader::Error("Syntax swShader::Error: oD%d index out of range", token->integer);
		}
		
		<O_FOG: "oFog">
		<O_POS: "oPos">
		<O_PTS: "oPts">
		
		<O_T: "oT"<DIGITS>>
		{
			token->integer = atoi(token->image().c_str() + 2);
			if(token->integer >= 8) throw swShader::Error("Syntax swShader::Error: oT%d index out of range", token->integer);
		}
		
		<L: "l"<DIGITS>>
		{
			token->integer = atoi(token->image().c_str() + 2);
			if(token->integer >= 16) throw swShader::Error("Syntax swShader::Error: l%d index out of range", token->integer);
		}
	}
}

{
#include "VS_2_0Assembler.hpp"

#include "Instruction.hpp"
#include "Operand.hpp"
#include "Error.hpp"

#include <string.h>
#include <list>

#pragma warning(disable : 4290)
#pragma warning(disable : 4786)
}

PARSER vs20_parser : public swShader::VS_2_0Assembler
{
	() main ()
	{
		(instruction() <EOL>+ {newInstruction();})*
		instruction()?

		catch(ScanException&) {throw swShader::Error("Syntax error");}
		catch(ParseException&) {throw swShader::Error("Parsing error");}
		catch(swShader::Error &error) {throw error;}
		catch(...) {throw swShader::INTERNAL_ERROR;}
	}

	() instruction ()
	{
		{
			m = swShader::Instruction::INVALID;
			usage_index = 0;
			x = swShader::Instruction::_NONE;
			d = swShader::voidOperand;
			s0 = swShader::voidOperand;
			s1 = swShader::voidOperand;
			s2 = swShader::voidOperand;
			s3 = swShader::voidOperand;
		}
	
		(
			absInstruction() |
			addInstruction() |
			callInstruction() |
			callnzInstruction() |
			crsInstruction() |
			dcl_positionInstruction() |
			dcl_blendweightInstruction() |
			dcl_blendindicesInstruction() |
			dcl_normalInstruction() |
			dcl_psizeInstruction() |
			dcl_texcoordInstruction() |
			dcl_tangentInstruction() |
			dcl_binormalInstruction() |
			dcl_tessfactorInstruction() |
			dcl_positiontInstruction() |
			dcl_colorInstruction() |
			dcl_fogInstruction() |
			dcl_depthInstruction() |
			dcl_sampleInstruction() |
			defInstruction() |
			defbInstruction() |
			defiInstruction() |
			dp3Instruction() |
			dp4Instruction() |
			dstInstruction() |
			elseInstruction() |
			endifInstruction() |
			endloopInstruction() |
			endrepInstruction() |
			expInstruction() |
			exppInstruction() |
			frcInstruction() |
			ifInstruction() |
			labelInstruction() |
			litInstruction() |
			logInstruction() |
			logpInstruction() |
			loopInstruction() |
			lrpInstruction() |
			m3x2Instruction() |
			m3x3Instruction() |
			m3x4Instruction() |
			m4x3Instruction() |
			m4x4Instruction() |
			madInstruction() |
			maxInstruction() |
			minInstruction() |
			movInstruction() |
			movaInstruction() |
			mulInstruction() |
			nopInstruction() |
			nrmInstruction() |
			powInstruction() |
			rcpInstruction() |
			repInstruction() |
			retInstruction() |
			rsqInstruction() |
			sgeInstruction() |
			sgnInstruction() |
			sincosInstruction() |
			sltInstruction() |
			vsInstruction()
		)
		
		catch(ParseException&) {throw swShader::Error("Expected an instruction");}
		
		{
			setMnemonic(m);
			setUsageIndex(usage_index);
			setModifier(x);
			setDestination(d);
			setSource0(s0);
			setSource1(s1);
			setSource2(s2);
			setSource3(s3);
		}
	}

	// Setup instructions
	() vsInstruction ()
	{
		<VS_2_0> {m = swShader::Instruction::VS_2_0;}
	}
	
	() dcl_positionInstruction ()
	{
		<DCL_POSITION> {m = swShader::Instruction::DCL_POSITION; usage_index = token->integer;}
		dest()
	}
	
	() dcl_blendweightInstruction ()
	{
		<DCL_BLENDWEIGHT> {m = swShader::Instruction::DCL_BLENDWEIGHT; usage_index = token->integer;}
		dest()
	}
	
	() dcl_blendindicesInstruction ()
	{
		<DCL_BLENDINDICES> {m = swShader::Instruction::DCL_BLENDINDICES; usage_index = token->integer;}
		dest()
	}
	
	() dcl_normalInstruction ()
	{
		<DCL_NORMAL> {m = swShader::Instruction::DCL_NORMAL; usage_index = token->integer;}
		dest()
	}
	
	() dcl_psizeInstruction ()
	{
		<DCL_PSIZE> {m = swShader::Instruction::DCL_PSIZE; usage_index = token->integer;}
		dest()
	}
	
	() dcl_texcoordInstruction ()
	{
		<DCL_TEXCOORD> {m = swShader::Instruction::DCL_TEXCOORD; usage_index = token->integer;}
		dest()
	}
	
	() dcl_tangentInstruction ()
	{
		<DCL_TANGENT> {m = swShader::Instruction::DCL_TANGENT; usage_index = token->integer;}
		dest()
	}
	
	() dcl_binormalInstruction ()
	{
		<DCL_BINORMAL> {m = swShader::Instruction::DCL_BINORMAL; usage_index = token->integer;}
		dest()
	}
	
	() dcl_tessfactorInstruction ()
	{
		<DCL_TESSFACTOR> {m = swShader::Instruction::DCL_TESSFACTOR; usage_index = token->integer;}
		dest()
	}
	
	() dcl_positiontInstruction ()
	{
		<DCL_POSITIONT> {m = swShader::Instruction::DCL_POSITIONT; usage_index = token->integer;}
		dest()
	}
	
	() dcl_colorInstruction ()
	{
		<DCL_COLOR> {m = swShader::Instruction::DCL_COLOR; usage_index = token->integer;}
		dest()
	}
	
	() dcl_fogInstruction ()
	{
		<DCL_FOG> {m = swShader::Instruction::DCL_FOG; usage_index = token->integer;}
		dest()
	}
	
	() dcl_depthInstruction ()
	{
		<DCL_DEPTH> {m = swShader::Instruction::DCL_DEPTH; usage_index = token->integer;}
		dest()
	}
	
	() dcl_sampleInstruction ()
	{
		<DCL_SAMPLE> {m = swShader::Instruction::DCL_SAMPLE; usage_index = token->integer;}
		dest()
	}
	
	() defInstruction ()
	{
		<DEF> {m = swShader::Instruction::DEF;}
		cn() <COMMA> fValue1() <COMMA> fValue2() <COMMA> fValue3() <COMMA> fValue4()
	}

	() defbInstruction ()
	{
		<DEFB> {m = swShader::Instruction::DEFB;}
		bn() <COMMA> booleanValue()
	}
	
	() defiInstruction ()
	{
		<DEFI> {m = swShader::Instruction::DEFI;}
		in() <COMMA> integerValue1() <COMMA> integerValue2() <COMMA> integerValue3() <COMMA> integerValue4()
	}

	// Arithmetic instructions
	() absInstruction ()
	{
		<ABS> {m = swShader::Instruction::ABS;} instructionModifier()
		dst() <COMMA> src()
	}
	
	() addInstruction ()
	{
		<ADD> {m = swShader::Instruction::ADD;} instructionModifier()
		dst() <COMMA> src0() <COMMA> src1()
	}
	
	() crsInstruction ()
	{
		<CRS> {m = swShader::Instruction::CRS;} instructionModifier()
		dst() <COMMA> src0() <COMMA> src1()
	}
	
	() dp3Instruction ()
	{
		<DP3> {m = swShader::Instruction::DP3;} instructionModifier()
		dst() <COMMA> src0() <COMMA> src1()
	}
	
	() dp4Instruction ()
	{
		<DP4> {m = swShader::Instruction::DP4;} instructionModifier()
		dst() <COMMA> src0() <COMMA> src1()
	}
	
	() dstInstruction ()
	{
		<DST> {m = swShader::Instruction::DST;} instructionModifier()
		dst() <COMMA> src0() <COMMA> src1()
	}
	
	() expInstruction ()
	{
		<EXP> {m = swShader::Instruction::EXP;} instructionModifier()
		dst() <COMMA> src()
	}

	() exppInstruction ()
	{
		<EXP> {m = swShader::Instruction::EXP;} instructionModifier()
		dst() <COMMA> src()
	}
	
	() frcInstruction ()
	{
		<FRC> {m = swShader::Instruction::FRC;} instructionModifier()
		dst() <COMMA> src()
	}
	
	() litInstruction ()
	{
		<LIT> {m = swShader::Instruction::LIT;} instructionModifier()
		dst() <COMMA> src()
	}	

	() logInstruction ()
	{
		<LOG> {m = swShader::Instruction::LOG;} instructionModifier()
		dst() <COMMA> src()
	}
	
	() logpInstruction ()
	{
		<LOGP> {m = swShader::Instruction::LOGP;} instructionModifier()
		dst() <COMMA> src()
	}
	
	() lrpInstruction ()
	{
		<LRP> {m = swShader::Instruction::LRP;} instructionModifier()
		dst() <COMMA> src0() <COMMA> src1() <COMMA> src2()
	}
	
	() m3x2Instruction ()
	{
		<M3X2> {m = swShader::Instruction::M3X2;} instructionModifier()
		dst() <COMMA> src0() <COMMA> src1()
	}
	
	() m3x3Instruction ()
	{
		<M3X3> {m = swShader::Instruction::M3X3;} instructionModifier()
		dst() <COMMA> src0() <COMMA> src1()
	}
	
	() m3x4Instruction ()
	{
		<M3X4> {m = swShader::Instruction::M3X4;} instructionModifier()
		dst() <COMMA> src0() <COMMA> src1()
	}
	
	() m4x3Instruction ()
	{
		<M4X3> {m = swShader::Instruction::M4X3;} instructionModifier()
		dst() <COMMA> src0() <COMMA> src1()
	}
	
	() m4x4Instruction ()
	{
		<M4X4> {m = swShader::Instruction::M4X4;} instructionModifier()
		dst() <COMMA> src0() <COMMA> src1()
	}
	
	() madInstruction ()
	{
		<MAD> {m = swShader::Instruction::MAD;} instructionModifier()
		dst() <COMMA> src0() <COMMA> src1() <COMMA> src2()
	}
	
	() maxInstruction ()
	{
		<MAX> {m = swShader::Instruction::MAX;} instructionModifier()
		dst() <COMMA> src0() <COMMA> src1()
	}
	
	() minInstruction ()
	{
		<MIN> {m = swShader::Instruction::MIN;} instructionModifier()
		dst() <COMMA> src0() <COMMA> src1()
	}
	
	() movInstruction ()
	{
		<MOV> {m = swShader::Instruction::MOV;} instructionModifier()
		(dst() | outputRegister()) <COMMA> src()
	}
	
	() movaInstruction ()
	{
		<MOVA> {m = swShader::Instruction::MOVA;} instructionModifier()
		a0() <COMMA> src()
	}
	
	() mulInstruction ()
	{
		<MUL> {m = swShader::Instruction::MUL;} instructionModifier()
		dst() <COMMA> src0() <COMMA> src1()
	}
	
	() nopInstruction ()
	{
		<NOP> {m = swShader::Instruction::NOP;}
	}
	
	() nrmInstruction ()
	{
		<NRM> {m = swShader::Instruction::NRM;} instructionModifier()
		dst() <COMMA> src()
	}
	
	() powInstruction ()
	{
		<POW> {m = swShader::Instruction::POW;} instructionModifier()
		dst() <COMMA> src0() <COMMA> src1()
	}
	
	() rcpInstruction ()
	{
		<RCP> {m = swShader::Instruction::RCP;} instructionModifier()
		dst() <COMMA> src()
	}
	
	() rsqInstruction ()
	{
		<RSQ> {m = swShader::Instruction::RSQ;} instructionModifier()
		dst() <COMMA> src()
	}
	
	() sgeInstruction ()
	{
		<SGE> {m = swShader::Instruction::SGE;} instructionModifier()
		dst() <COMMA> src0() <COMMA> src1()
	}
	
	() sgnInstruction ()
	{
		<SGN> {m = swShader::Instruction::SGN;} instructionModifier()
		dst() <COMMA> src0() <COMMA> src1() <COMMA> src2()
	}
	
	() sincosInstruction ()
	{
		<SINCOS> {m = swShader::Instruction::SINCOS;} instructionModifier()
		dst() <COMMA> src0() <COMMA> src1() <COMMA> src2()
	}
	
	() sltInstruction ()
	{
		<SLT> {m = swShader::Instruction::SLT;} instructionModifier()
		dst() <COMMA> src0() <COMMA> src1()
	}

	// Flow-control instruction
	() callInstruction ()
	{
		<CALL> {m = swShader::Instruction::CALL;}
		<INTEGER>
		{
			d.index = atoi(token->image().c_str());
			if(d.index < 0 || d.index >= 16) throw swShader::Error("Label index (%d) out of range", d.index);
		}
	}

	() callnzInstruction ()
	{
		<CALL> {m = swShader::Instruction::CALL;}
		<INTEGER>
		{
			d.index = atoi(token->image().c_str());
			if(d.index < 0 || d.index >= 16) throw swShader::Error("Label index (%d) out of range", d.index);
		}
		<COMMA>
		constantBooleanRegister() {s0 = t;}
	}
	
	() elseInstruction ()
	{
		<ELSE> {m = swShader::Instruction::ELSE;}
	}
	
	() endifInstruction()
	{
		<ENDIF> {m = swShader::Instruction::ENDIF;}
	}
	
	() endloopInstruction ()
	{
		<ENDLOOP> {m = swShader::Instruction::ENDLOOP;}
	}

	() endrepInstruction ()
	{
		<ENDREP> {m = swShader::Instruction::ENDREP;}
	}

	() ifInstruction()
	{
		<IF> {m = swShader::Instruction::IF;}
		constantBooleanRegister() {d = t; s0 = t;}
	}
	
	() labelInstruction ()
	{
		<L>
		{
			m = swShader::Instruction::LABEL;
			d.index = token->integer;
			s0.index = token->integer;
		}
	}
	
	() loopInstruction ()
	{
		<LOOP> {m = swShader::Instruction::LOOP;}
		aL()
		<COMMA>
		constantIntegerRegister() {s0 = t;}
	}

	() repInstruction ()
	{
		<REP> {m = swShader::Instruction::REP;}
		constantIntegerRegister() {d = t; s0 = t;}
	}
	
	() retInstruction ()
	{
		<RET> {m = swShader::Instruction::RET;}
	}

	// Modifiers and registers
	() instructionModifier ()
	{
		{
			x = swShader::Instruction::_NONE;
		}
		
		(
			<_SAT> {x = swShader::Instruction::_SAT;}
		)?
	}

	() dst ()
	{
		(temporaryRegister() writeMask())
		
		catch(ParseException&) {throw swShader::Error("Expected a temporary register r#");}
	
		{d = t;}
	}
	
	() dest ()
	{
		vertexRegister()
				
		catch(ParseException&) {throw swShader::Error("Expected a register v#");}
	
		{d = t;}
	}
	
	() a0 ()
	{
		a0Register()
		
		catch(ParseException&) {throw swShader::Error("Expected a0");}
		
		{d = t;}
	}
	
	() aL ()
	{
		aLRegister()
		
		catch(ParseException&) {throw swShader::Error("Expected aL");}
		
		{d = t;}
	}
	
	() cn ()
	{
		constantFloatRegister()
		
		catch(ParseException&) {throw swShader::Error("Expected a constant float register c#");}

		{d = t;}
	}

	() bn ()
	{
		constantBooleanRegister()
		
		catch(ParseException&) {throw swShader::Error("Expected a boolean register c#");}

		{d = t;}
	}

	() in ()
	{
		constantIntegerRegister()
		
		catch(ParseException&) {throw swShader::Error("Expected a boolean register c#");}

		{d = t;}
	}
	
	() fValue1 ()
	{
		(<REAL> | <INTEGER>)
		
		catch(ParseException&) {throw swShader::Error("Expected a floating-point literal");}

		{s0.value = (float)strtod(token->image().c_str(), 0);}
	}

	() fValue2 ()
	{
		(<REAL> | <INTEGER>)
		
		catch(ParseException&) {throw swShader::Error("Expected a floating-point literal");}

		{s1.value = (float)strtod(token->image().c_str(), 0);}
	}
	
	() fValue3 ()
	{
		(<REAL> | <INTEGER>)
		
		catch(ParseException&) {throw swShader::Error("Expected a floating-point literal");}

		{s2.value = (float)strtod(token->image().c_str(), 0);}
	}
	
	() fValue4 ()
	{
		(<REAL> | <INTEGER>)
		
		catch(ParseException&) {throw swShader::Error("Expected a floating-point literal");}

		{s3.value = (float)strtod(token->image().c_str(), 0);}
	}
	
	() integerValue1 ()
	{
		<INTEGER>
		
		catch(ParseException&) {throw swShader::Error("Expected an integer literal");}

		{s0.integer = atoi(token->image().c_str());}
	}

	() integerValue2 ()
	{
		<INTEGER>
		
		catch(ParseException&) {throw swShader::Error("Expected an integer literal");}

		{s1.integer = atoi(token->image().c_str());}
	}
	
	() integerValue3 ()
	{
		<INTEGER>
		
		catch(ParseException&) {throw swShader::Error("Expected an integer literal");}

		{s2.integer = atoi(token->image().c_str());}
	}
	
	() integerValue4 ()
	{
		<INTEGER>
		
		catch(ParseException&) {throw swShader::Error("Expected an integer literal");}

		{s3.integer = atoi(token->image().c_str());}
	}
	
	() booleanValue ()
	{
		(<TRUE> | <FALSE>)
		
		catch(ParseException&) {throw swShader::Error("Expected a boolean");}

		{s3.boolean = token->integer != 0;}
	}
	
	() src ()
	{
		(sourceModifier() inputRegister() sourceSwizzle()) {s0 = t;}
	}

	() src0 ()
	{
		(sourceModifier() inputRegister() sourceSwizzle()) {s0 = t;}
	}
	
	() src1 ()
	{
		(sourceModifier() inputRegister() sourceSwizzle()) {s1 = t;}
	}
	
	() src2 ()
	{
		(sourceModifier() inputRegister() sourceSwizzle()) {s2 = t;}
	}
	
	() outputRegister()
	{
		(diffuseSpecularRegister() |
		 fogRegister() |
		 positionRegister() |
		 pointSizeRegister() |
		 textureCoordinateRegister())
		
		{d = t;}
	}
	
	() inputRegister ()
	{
		vertexRegister() |
		temporaryRegister() |
		constantFloatRegister()
	}
	
	() sourceModifier ()
	{
		{t.mod = swShader::Operand::SourceModifier::NONE;}
	
		(
			<MINUS>
			
			{t.mod = swShader::Operand::SourceModifier::NEGATE;}
		)?
	}
	
	() writeMask ()
	{
		{
			// Mask all components
			t.sel.x = swShader::Operand::X;
			t.sel.y = swShader::Operand::Y;
			t.sel.z = swShader::Operand::Z;
			t.sel.w = swShader::Operand::W;
		}
	
		(
			<DOT>
			
			{
				// Mask all components
				t.sel.x = swShader::Operand::M;
				t.sel.y = swShader::Operand::M;
				t.sel.z = swShader::Operand::M;
				t.sel.w = swShader::Operand::M;
			}
			
			(
				(
					(<X> {t.sel.x = swShader::Operand::X;})
					(<Y> {t.sel.y = swShader::Operand::Y;})?
					(<Z> {t.sel.z = swShader::Operand::Z;})?
					(<W> {t.sel.w = swShader::Operand::W;})?
				)
					|
				(
					(<Y> {t.sel.y = swShader::Operand::Y;})
					(<Z> {t.sel.z = swShader::Operand::Z;})?
					(<W> {t.sel.w = swShader::Operand::W;})?
				) 
					|
				(
					(<Z> {t.sel.z = swShader::Operand::Z;}) 
					(<W> {t.sel.w = swShader::Operand::W;})?
				) 
					|
				(
					(<W> {t.sel.w = swShader::Operand::W;})
				)
			)
		)?
	}

	() sourceSwizzle ()
	{
		{
			t.sel.x = swShader::Operand::Component::X;
			t.sel.y = swShader::Operand::Component::Y;
			t.sel.z = swShader::Operand::Component::Z;
			t.sel.w = swShader::Operand::Component::W;
		}
	
		(
			<DOT>
			
			(
				(<X> {t.sel.x = swShader::Operand::X; t.sel.y = swShader::Operand::X; t.sel.z = swShader::Operand::X; t.sel.w = swShader::Operand::X;}) |
				(<Y> {t.sel.x = swShader::Operand::Y; t.sel.y = swShader::Operand::Y; t.sel.z = swShader::Operand::Y; t.sel.w = swShader::Operand::Y;}) |
				(<Z> {t.sel.x = swShader::Operand::Z; t.sel.y = swShader::Operand::Z; t.sel.z = swShader::Operand::Z; t.sel.w = swShader::Operand::Z;}) |
				(<W> {t.sel.x = swShader::Operand::W; t.sel.y = swShader::Operand::W; t.sel.z = swShader::Operand::W; t.sel.w = swShader::Operand::W;})
			)
			(
				(<X> {t.sel.y = swShader::Operand::X; t.sel.z = swShader::Operand::X; t.sel.w = swShader::Operand::X;}) |
				(<Y> {t.sel.y = swShader::Operand::Y; t.sel.z = swShader::Operand::Y; t.sel.w = swShader::Operand::Y;}) |
				(<Z> {t.sel.y = swShader::Operand::Z; t.sel.z = swShader::Operand::Z; t.sel.w = swShader::Operand::Z;}) |
				(<W> {t.sel.y = swShader::Operand::W; t.sel.z = swShader::Operand::W; t.sel.w = swShader::Operand::W;})
			)?
			(
				(<X> {t.sel.z = swShader::Operand::X; t.sel.w = swShader::Operand::X;}) |
				(<Y> {t.sel.z = swShader::Operand::Y; t.sel.w = swShader::Operand::Y;}) |
				(<Z> {t.sel.z = swShader::Operand::Z; t.sel.w = swShader::Operand::Z;}) |
				(<W> {t.sel.z = swShader::Operand::W; t.sel.w = swShader::Operand::W;})
			)?
			(
				(<X> {t.sel.w = swShader::Operand::X;}) |
				(<Y> {t.sel.w = swShader::Operand::Y;}) |
				(<Z> {t.sel.w = swShader::Operand::Z;}) |
				(<W> {t.sel.w = swShader::Operand::W;})
			)?
		)?
	}
	
	() vertexRegister ()
	{
		<V> {t.type = swShader::Operand::INPUT_REGISTER; t.index = token->integer;}
	}
	
	() temporaryRegister ()
	{
		<R> {t.type = swShader::Operand::TEMPORARY_REGISTER; t.index = token->integer;}
	}
	
	() constantFloatRegister ()
	{
		<C> {t.type = swShader::Operand::CONSTANT_FLOAT_REGISTER; t.index = token->integer;}
	}
	
	() constantIntegerRegister ()
	{
		<I> {t.type = swShader::Operand::CONSTANT_INTEGER_REGISTER; t.index = token->integer;}
	}
	
	() constantBooleanRegister ()
	{
		<B> {t.type = swShader::Operand::CONSTANT_BOOLEAN_REGISTER; t.index = token->integer;}
	}
	
	() a0Register ()
	{
		<A0> {t.type = swShader::Operand::ADDRESS_REGISTER; t.index = 0;}
	}
	
	() aLRegister ()
	{
		<AL> {t.type = swShader::Operand::LOOP_COUNTER_REGISTER; t.index = 0;}
	}
	
	() diffuseSpecularRegister ()
	{
		<O_D> {t.type = swShader::Operand::DIFFUSE_SPECULAR_REGISTER; t.index = token->integer;}
	}
	
	() fogRegister ()
	{
		<O_FOG> {t.type = swShader::Operand::FOG_REGISTER; t.index = 0;}
	}
	
	() positionRegister ()
	{
		<O_POS> {t.type = swShader::Operand::POSITION_REGISTER; t.index = 0;}
	}
	
	() pointSizeRegister ()
	{
		<O_PTS> {t.type = swShader::Operand::POINT_SIZE_REGISTER; t.index = 0;}
	}
	
	() textureCoordinateRegister ()
	{
		<O_T> {t.type = swShader::Operand::TEXTURE_COORDINATE_REGISTER; t.index = token->integer;}
	}

	{
	private:
		swShader::Operand t;   // Temporary operand
	
		swShader::Instruction::Mnemonic m;  // Operation
		int usage_index;   // Vertex shader dcl
		swShader::Instruction::Modifier x;  // Instrution modifier
		swShader::Operand d;   // Destination
		swShader::Operand s0;   // Source 0
		swShader::Operand s1;   // Source 1
		swShader::Operand s2;   // Source 2
		swShader::Operand s3;   // Source 3
	}
}
