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 = "swShader";
	SRC_EXTENSION = "cpp";
	HDR_EXTENSION = "hpp";
}

{ 
#pragma warning(disable : 4290)
#pragma warning(disable : 4786)
}

TOKEN ps20_token
{
public:
	int integer;
	double real;
}

{
#pragma warning(disable : 4290)
#pragma warning(disable : 4786)
}

SCANNER ps20_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
	{
		<PS_2_0: "ps_2_0">
		<DCL: "dcl">
		<DCL_2D: "dcl_2d">
		<DCL_CUBE: "dcl_cube">
		<DCL_VOLUME: "dcl_volume">	
		<DEF: "def">
	
		<ABS: "abs">
		<ADD: "add">
		<CMP: "cmp">
		<CRS: "crs">
		<DP2ADD: "dp2add">
		<DP3: "dp3">
		<DP4: "dp4">
		<EXP: "exp">
		<FRC: "frc">
		<LOG: "log">
		<LRP: "lrp">
		<M3X2: "m3x2">
		<M3X3: "m3x3">
		<M3X4: "m3x4">
		<M4X3: "m4x3">
		<M4X4: "m4x4">
		<MAD: "mad">
		<MAX: "max">
		<MIN: "min">
		<MOV: "mov">
		<MUL: "mul">
		<NOP: "nop">
		<NRM: "nrm">
		<POW: "pow">
		<RCP: "rcp">
		<RSQ: "rsq">
		<SINCOS: "sincos">
		<SUB: "sub">
		
		<TEXKILL: "texkill">
		<TEXLD: "texld">
		<TEXLDB: "texldb">
		<TEXLDP: "texldp">
		
		<_SAT: "_sat">
		<_PP: "_pp">
	}

	<START> KEYWORD
	{
		<V0: "v0"> 
		<V1: "v1">

		<C0: "c0">
		<C1: "c1">
		<C2: "c2">
		<C3: "c3">
		<C4: "c4">
		<C5: "c5">
		<C6: "c6">
		<C7: "c7">
		<C8: "c8">
		<C9: "c9">
		<C10: "c10">
		<C11: "c11">
		<C12: "c12">
		<C13: "c13">
		<C14: "c14">
		<C15: "c15">
		<C16: "c16">
		<C17: "c17">
		<C18: "c18">
		<C19: "c19">
		<C20: "c20">
		<C21: "c21">
		<C22: "c22">
		<C23: "c23">
		<C24: "c24">
		<C25: "c25">
		<C26: "c26">
		<C27: "c27">
		<C28: "c28">
		<C29: "c29">
		<C30: "c30">
		<C31: "c31">

		<T0: "t0">
		<T1: "t1">
		<T2: "t2">
		<T3: "t3">
		<T4: "t4">
		<T5: "t5">
		<T6: "t6">
		<T7: "t7">

		<S0: "s0">
		<S1: "s1">
		<S2: "s2">
		<S3: "s3">
		<S4: "s4">
		<S5: "s5">
		<S6: "s6">
		<S7: "s7">
		<S8: "s8">
		<S9: "s9">
		<S10: "s10">
		<S11: "s11">
		<S12: "s12">
		<S13: "s13">
		<S14: "s14">
		<S15: "s15">

		<R0: "r0">
		<R1: "r1">
		<R2: "r2">
		<R3: "r3">
		<R4: "r4">
		<R5: "r5">
		<R6: "r6">
		<R7: "r7">
		<R8: "r8">
		<R9: "r9">
		<R10: "r10">
		<R11: "r11">

		<O_C0: "oC0">
		<O_C1: "oC1">
		<O_C2: "oC2">
		<O_C3: "oC3">

		<O_DEPTH: "oDepth">
	}
	
	<START> KEYWORD
	{
		<X: "x" | "r">
		<Y: "y" | "g">
		<Z: "z" | "b">
		<W: "w" | "a">
	}

	<START> KEYWORD
	{
		<COMMA: ",">
		<DOT: ".">
		<MINUS: "-">
	}

	<START> TOKEN
	{
		<#DIGIT: ['0'-'9']>
		<#DIGITS: <DIGIT>+>
		<#SIGN: ['+','-']>
		<#EXPONENT: ['e', 'E']>
		<INTEGER: <SIGN>? <DIGITS>>
		<REAL: (<SIGN>? <DIGITS>? ("." <DIGITS>) |
		        (("." <DIGITS>)? <EXPONENT> <SIGN>? <DIGITS>)) "f"?>
	}
}

{
#include "PS20Assembler.hpp"

#include "Instruction.hpp"
#include "Operand.hpp"
#include "Error.hpp"
using namespace swShader;

#include <string.h>
#include <list>

#pragma warning(disable : 4290)
#pragma warning(disable : 4786)
}

PARSER ps20_parser : public PS20Assembler
{
	() main ()
	{
		(instruction() <EOL>+ {newInstruction();})*
		instruction()?

		catch(ScanException&) {throw Error("Syntax error");}
		catch(ParseException&) {throw Error("Parsing error");}
		catch(Error &error) {throw error;}
		catch(...) {throw INTERNAL_ERROR;}
	}

	() instruction ()
	{
		{
			m = Instruction::INVALID;
			x = Instruction::_NONE;
			d = voidOperand;
			s0 = voidOperand;
			s1 = voidOperand;
			s2 = voidOperand;
			s3 = voidOperand;
		}
	
		(
			absInstruction() |
			addInstruction() |
			cmpInstruction() |
			crsInstruction() |
			dclInstruction() |
			dcl_2dInstruction() |
			dcl_cubeInstruction() |
			dcl_volumeInstruction() |
			defInstruction() |
			dp2addInstruction() |
			dp3Instruction() |
			dp4Instruction() |
			expInstruction() |
			frcInstruction() |
			logInstruction() |
			lrpInstruction() |
			m3x2Instruction() |
			m3x3Instruction() |
			m3x4Instruction() |
			m4x3Instruction() |
			m4x4Instruction() |
			madInstruction() |
			maxInstruction() |
			minInstruction() |
			movInstruction() |
			mulInstruction() |
			nopInstruction() |
			nrmInstruction() |
			powInstruction() |
			psInstruction() |
			rcpInstruction() |
			rsqInstruction() |
			sincosInstruction() |
			subInstruction() |
			texkillInstruction() |
			texldInstruction() |
			texldbInstruction() |
			texldpInstruction()
		)
		
		catch(ParseException&) {throw Error("Expected an instruction");}
		
		{
			setMnemonic(m);
			setModifier(x);
			setDestination(d);
			setSource0(s0);
			setSource1(s1);
			setSource2(s2);
			setSource3(s3);
		}
	}

	// Setup instructions
	() psInstruction ()
	{
		<PS_2_0> {m = Instruction::PS_2_0;}
	}
	
	() dclInstruction ()
	{
		<DCL> {m = Instruction::DCL;}
		dest()
	}
		
	() dcl_2dInstruction ()
	{
		<DCL_2D> {m = Instruction::DCL_2D;}
		sn()
	}
	
	() dcl_cubeInstruction ()
	{
		<DCL_CUBE> {m = Instruction::DCL_CUBE;}
		sn()
	}
	
	() dcl_volumeInstruction ()
	{
		<DCL_VOLUME> {m = Instruction::DCL_VOLUME;}
		sn()
	}
	
	() defInstruction ()
	{
		<DEF> {m = Instruction::DEF;}
		cn() <COMMA> fValue1() <COMMA> fValue2() <COMMA> fValue3() <COMMA> fValue4()
	}

	// Arithmetic instructions
	() absInstruction ()
	{
		<ABS> {m = Instruction::ABS;} instructionModifier()
		dst() <COMMA> src()
	}
	
	() addInstruction ()
	{
		<ADD> {m = Instruction::ADD;} instructionModifier()
		dst() <COMMA> src0() <COMMA> src1()
	}
	
	() cmpInstruction ()
	{
		<CMP> {m = Instruction::CMP;} instructionModifier()
		dst() <COMMA> src0() <COMMA> src1() <COMMA> src2()
	}
	
	() crsInstruction ()
	{
		<CRS> {m = Instruction::CRS;} instructionModifier()
		dst() <COMMA> src0() <COMMA> src1()
	}
	
	() dp2addInstruction ()
	{
		<DP2ADD> {m = Instruction::DP2ADD;} instructionModifier()
		dst() <COMMA> src0() <COMMA> src1() <COMMA> src2()
	}
	
	() dp3Instruction ()
	{
		<DP3> {m = Instruction::DP3;} instructionModifier()
		dst() <COMMA> src0() <COMMA> src1()
	}
	
	() dp4Instruction ()
	{
		<DP4> {m = Instruction::DP4;} instructionModifier()
		dst() <COMMA> src0() <COMMA> src1()
	}
	
	() expInstruction ()
	{
		<EXP> {m = Instruction::EXP;} instructionModifier()
		dst() <COMMA> src()
	}
	
	() frcInstruction ()
	{
		<FRC> {m = Instruction::FRC;} instructionModifier()
		dst() <COMMA> src()
	}
	
	() logInstruction ()
	{
		<LOG> {m = Instruction::LOG;} instructionModifier()
		dst() <COMMA> src()
	}
	
	() lrpInstruction ()
	{
		<LRP> {m = Instruction::LRP;} instructionModifier()
		dst() <COMMA> src0() <COMMA> src1() <COMMA> src2()
	}
	
	() m3x2Instruction ()
	{
		<M3X2> {m = Instruction::M3X2;} instructionModifier()
		dst() <COMMA> src0() <COMMA> src1()
	}
	
	() m3x3Instruction ()
	{
		<M3X3> {m = Instruction::M3X3;} instructionModifier()
		dst() <COMMA> src0() <COMMA> src1()
	}
	
	() m3x4Instruction ()
	{
		<M3X4> {m = Instruction::M3X4;} instructionModifier()
		dst() <COMMA> src0() <COMMA> src1()
	}
	
	() m4x3Instruction ()
	{
		<M4X3> {m = Instruction::M4X3;} instructionModifier()
		dst() <COMMA> src0() <COMMA> src1()
	}
	
	() m4x4Instruction ()
	{
		<M4X4> {m = Instruction::M4X4;} instructionModifier()
		dst() <COMMA> src0() <COMMA> src1()
	}
	
	() madInstruction ()
	{
		<MAD> {m = Instruction::MAD;} instructionModifier()
		dst() <COMMA> src0() <COMMA> src1() <COMMA> src2()
	}
	
	() maxInstruction ()
	{
		<MAX> {m = Instruction::MAX;} instructionModifier()
		dst() <COMMA> src0() <COMMA> src1()
	}
	
	() minInstruction ()
	{
		<MIN> {m = Instruction::MIN;} instructionModifier()
		dst() <COMMA> src0() <COMMA> src1()
	}
	
	() movInstruction ()
	{
		<MOV> {m = Instruction::MOV;} instructionModifier()
		(dst() | outputRegister()) <COMMA> src()
	}
	
	() mulInstruction ()
	{
		<MUL> {m = Instruction::MUL;} instructionModifier()
		dst() <COMMA> src0() <COMMA> src1()
	}
	
	() nopInstruction ()
	{
		<NOP> {m = Instruction::NOP;}
	}
	
	() nrmInstruction ()
	{
		<NRM> {m = Instruction::NRM;} instructionModifier()
		dst() <COMMA> src()
	}
	
	() powInstruction ()
	{
		<POW> {m = Instruction::POW;} instructionModifier()
		dst() <COMMA> src0() <COMMA> src1()
	}
	
	() rcpInstruction ()
	{
		<RCP> {m = Instruction::RCP;} instructionModifier()
		dst() <COMMA> src()
	}
	
	() rsqInstruction ()
	{
		<RSQ> {m = Instruction::RSQ;} instructionModifier()
		dst() <COMMA> src()
	}
	
	() sincosInstruction ()
	{
		<SINCOS> {m = Instruction::SINCOS;} instructionModifier()
		dst() <COMMA> src0() <COMMA> src1() <COMMA> src2()
	}
	
	() subInstruction ()
	{
		<SUB> {m = Instruction::SUB;} instructionModifier()
		dst() <COMMA> src0() <COMMA> src1()
	}
	
	// Texture instructions
	() texkillInstruction ()
	{
		<TEXKILL> {m = Instruction::TEXKILL;}
		dst() <COMMA> src0() <COMMA> src1()
	}
	
	() texldInstruction ()
	{
		<TEXLD>	{m = Instruction::TEXLD;}
		dst() <COMMA> src0() <COMMA> src1()
	}
	
	() texldbInstruction ()
	{
		<TEXLDB> {m = Instruction::TEXLDB;}
		dst() <COMMA> src0() <COMMA> src1()
	}
	
	() texldpInstruction ()
	{
		<TEXLDP> {m = Instruction::TEXLDP;}
		dst() <COMMA> src0() <COMMA> src1()
	}

	() instructionModifier ()
	{
		{
			x = Instruction::_NONE;
		}
		
		(
			(<_SAT> {x = Instruction::_SAT;}) |
			(<_PP> {x = Instruction::_PP;})
		)?
	}

	() dst ()
	{
		(temporaryRegister() writeMask())
		
		catch(ParseException&) {throw Error("Expected a temporary register r#");}
	
		{d = t;}
	}
	
	() dest ()
	{
		(colorRegister() | inputTextureCoordinateRegister())
		
		catch(ParseException&) {throw Error("Expected a register v# or t#");}
	
		{d = t;}
	}
	
	() sn ()
	{
		samplerRegister()

		catch(ParseException&) {throw Error("Expected a sampler register s#");}

		{d = t;}
	}
	
	() cn ()
	{
		constantFloatRegister()
		
		catch(ParseException&) {throw Error("Expected a constant float register c#");}

		{d = t;}
	}
	
	() fValue1 ()
	{
		(<REAL> | <INTEGER>)
		
		catch(ParseException&) {throw Error("Expected a floating-point literal");}

		{s0.value = (float)strtod(token->image().c_str(), 0);}
	}

	() fValue2 ()
	{
		(<REAL> | <INTEGER>)
		
		catch(ParseException&) {throw Error("Expected a floating-point literal");}

		{s1.value = (float)strtod(token->image().c_str(), 0);}
	}
	
	() fValue3 ()
	{
		(<REAL> | <INTEGER>)
		
		catch(ParseException&) {throw Error("Expected a floating-point literal");}

		{s2.value = (float)strtod(token->image().c_str(), 0);}
	}
	
	() fValue4 ()
	{
		(<REAL> | <INTEGER>)
		
		catch(ParseException&) {throw Error("Expected a floating-point literal");}

		{s3.value = (float)strtod(token->image().c_str(), 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()
	{
		(outputColorRegister() | outputDepthRegister()) {d = t;}
	}
	
	() inputRegister ()
	{
		colorRegister() |
		constantFloatRegister() |
		inputTextureCoordinateRegister() |
		samplerRegister() |
		temporaryRegister()
	}
	
	() sourceModifier ()
	{
		{t.mod = Operand::SourceModifier::NONE;}
	
		(
			<MINUS>
			
			{t.mod = Operand::SourceModifier::NEGATE;}
		)?
	}
	
	() writeMask ()
	{
		{
			// Mask all components
			t.sel.x = Operand::X;
			t.sel.y = Operand::Y;
			t.sel.z = Operand::Z;
			t.sel.w = Operand::W;
		}
	
		(
			<DOT>
			
			{
				// Mask all components
				t.sel.x = Operand::M;
				t.sel.y = Operand::M;
				t.sel.z = Operand::M;
				t.sel.w = Operand::M;
			}
			
			(
				(
					(<X> {t.sel.x = Operand::X;})
					(<Y> {t.sel.y = Operand::Y;})?
					(<Z> {t.sel.z = Operand::Z;})?
					(<W> {t.sel.w = Operand::W;})?
				)
					|
				(
					(<Y> {t.sel.y = Operand::Y;})
					(<Z> {t.sel.z = Operand::Z;})?
					(<W> {t.sel.w = Operand::W;})?
				) 
					|
				(
					(<Z> {t.sel.z = Operand::Z;}) 
					(<W> {t.sel.w = Operand::W;})?
				) 
					|
				(
					(<W> {t.sel.w = Operand::W;})
				)
			)
		)?
	}

	() sourceSwizzle ()
	{
		{
			t.sel.x = Operand::Component::X;
			t.sel.y = Operand::Component::Y;
			t.sel.z = Operand::Component::Z;
			t.sel.w = Operand::Component::W;
		}
	
		(
			<DOT>
			
			(
				(<X> {t.sel.x = Operand::X; t.sel.y = Operand::X; t.sel.z = Operand::X; t.sel.w = Operand::X;}) |
				(<Y> {t.sel.x = Operand::Y; t.sel.y = Operand::Y; t.sel.z = Operand::Y; t.sel.w = Operand::Y;}) |
				(<Z> {t.sel.x = Operand::Z; t.sel.y = Operand::Z; t.sel.z = Operand::Z; t.sel.w = Operand::Z;}) |
				(<W> {t.sel.x = Operand::W; t.sel.y = Operand::W; t.sel.z = Operand::W; t.sel.w = Operand::W;})
			)
			(
				(<X> {t.sel.y = Operand::X; t.sel.z = Operand::X; t.sel.w = Operand::X;}) |
				(<Y> {t.sel.y = Operand::Y; t.sel.z = Operand::Y; t.sel.w = Operand::Y;}) |
				(<Z> {t.sel.y = Operand::Z; t.sel.z = Operand::Z; t.sel.w = Operand::Z;}) |
				(<W> {t.sel.y = Operand::W; t.sel.z = Operand::W; t.sel.w = Operand::W;})
			)?
			(
				(<X> {t.sel.z = Operand::X; t.sel.w = Operand::X;}) |
				(<Y> {t.sel.z = Operand::Y; t.sel.w = Operand::Y;}) |
				(<Z> {t.sel.z = Operand::Z; t.sel.w = Operand::Z;}) |
				(<W> {t.sel.z = Operand::W; t.sel.w = Operand::W;})
			)?
			(
				(<X> {t.sel.w = Operand::X;}) |
				(<Y> {t.sel.w = Operand::Y;}) |
				(<Z> {t.sel.w = Operand::Z;}) |
				(<W> {t.sel.w = Operand::W;})
			)?
		)?
	}
	
	() colorRegister ()
	{
		<V0>	{t.reg = v0Register;} |
		<V1>	{t.reg = v1Register;}
	}
	
	() constantFloatRegister ()
	{
		<C0>	{t.reg = c0Register;} |
		<C1>	{t.reg = c1Register;} |
		<C2>	{t.reg = c2Register;} |
		<C3>	{t.reg = c3Register;} |
		<C4>	{t.reg = c4Register;} |
		<C5>	{t.reg = c5Register;} |
		<C6>	{t.reg = c6Register;} |
		<C7>	{t.reg = c7Register;} |
		<C8>	{t.reg = c8Register;} |
		<C9>	{t.reg = c9Register;} |
		<C10>	{t.reg = c10Register;} |
		<C11>	{t.reg = c11Register;} |
		<C12>	{t.reg = c12Register;} |
		<C13>	{t.reg = c13Register;} |
		<C14>	{t.reg = c14Register;} |
		<C15>	{t.reg = c15Register;} |
		<C16>	{t.reg = c16Register;} |
		<C17>	{t.reg = c17Register;} |
		<C18>	{t.reg = c18Register;} |
		<C19>	{t.reg = c19Register;} |
		<C20>	{t.reg = c20Register;} |
		<C21>	{t.reg = c21Register;} |
		<C22>	{t.reg = c22Register;} |
		<C23>	{t.reg = c23Register;} |
		<C24>	{t.reg = c24Register;} |
		<C25>	{t.reg = c25Register;} |
		<C26>	{t.reg = c26Register;} |
		<C27>	{t.reg = c27Register;} |
		<C28>	{t.reg = c28Register;} |
		<C29>	{t.reg = c29Register;} |
		<C30>	{t.reg = c30Register;} |
		<C31>	{t.reg = c31Register;}
	}

	() inputTextureCoordinateRegister ()
	{
		(
			<T0>	{t.reg = t0Register;} |
			<T1>	{t.reg = t1Register;} |
			<T2>	{t.reg = t2Register;} |
			<T3>	{t.reg = t3Register;} |
			<T4>	{t.reg = t4Register;} |
			<T5>	{t.reg = t5Register;} |
			<T6>	{t.reg = t6Register;} |
			<T7>	{t.reg = t7Register;}
		)

		writeMask()?
	}
	
	() samplerRegister ()
	{
		<S0>	{t.reg = s0Register;} |
		<S1>	{t.reg = s1Register;} |
		<S2>	{t.reg = s2Register;} |
		<S3>	{t.reg = s3Register;} |
		<S4>	{t.reg = s4Register;} |
		<S5>	{t.reg = s5Register;} |
		<S6>	{t.reg = s6Register;} |
		<S7>	{t.reg = s7Register;} |
		<S8>	{t.reg = s8Register;} |
		<S9>	{t.reg = s9Register;} |
		<S10>	{t.reg = s10Register;} |
		<S11>	{t.reg = s11Register;} |
		<S12>	{t.reg = s12Register;} |
		<S13>	{t.reg = s13Register;} |
		<S14>	{t.reg = s14Register;} |
		<S15>	{t.reg = s15Register;}
	}

	() temporaryRegister ()
	{
		<R0>	{t.reg = r0Register;} |
		<R1>	{t.reg = r1Register;} |
		<R2>	{t.reg = r2Register;} |
		<R3>	{t.reg = r3Register;} |
		<R4>	{t.reg = r4Register;} |
		<R5>	{t.reg = r5Register;} |
		<R6>	{t.reg = r6Register;} |
		<R7>	{t.reg = r7Register;} |
		<R8>	{t.reg = r8Register;} |
		<R9>	{t.reg = r9Register;} |
		<R10>	{t.reg = r10Register;} |
		<R11>	{t.reg = r11Register;}
	}

	() outputColorRegister ()
	{
		<O_C0>	{t.reg = oC0Register;} |
		<O_C1>	{t.reg = oC1Register;} |
		<O_C2>	{t.reg = oC2Register;} |
		<O_C3>	{t.reg = oC3Register;}
	}

	() outputDepthRegister ()
	{
		<O_DEPTH>	{t.reg = oDepthRegister;}
	}

	{
	private:
		Operand t;   // Temporary operand
	
		Instruction::Mnemonic m;  // Operation
		Instruction::Modifier x;  // Instrution modifier
		Operand d;   // Destination
		Operand s0;   // Source 0
		Operand s1;   // Source 1
		Operand s2;   // Source 2
		Operand s3;   // Source 3
	}
}
