[5/18] d3dx9: Add base assembler lexer and parser

Matteo Bruni matteo.mystral at gmail.com
Sun Aug 16 12:51:52 CDT 2009


-------------- next part --------------
From 2a73fabcc0e8f8c95a11509f6a21ee2048b069e9 Mon Sep 17 00:00:00 2001
From: Matteo Bruni <matteo.mystral at gmail.com>
Date: Sat, 15 Aug 2009 18:27:58 +0200
Subject: d3dx9: Add base assembler lexer and parser

---
 dlls/d3dx9_36/Makefile.in |    6 +
 dlls/d3dx9_36/asmparser.c |  156 +++++
 dlls/d3dx9_36/asmshader.l |  552 ++++++++++++++++
 dlls/d3dx9_36/asmshader.y | 1606 +++++++++++++++++++++++++++++++++++++++++++++
 4 files changed, 2320 insertions(+), 0 deletions(-)
 create mode 100644 dlls/d3dx9_36/asmparser.c
 create mode 100644 dlls/d3dx9_36/asmshader.l
 create mode 100644 dlls/d3dx9_36/asmshader.y

diff --git a/dlls/d3dx9_36/Makefile.in b/dlls/d3dx9_36/Makefile.in
index 88ac1d7..87788d8 100644
--- a/dlls/d3dx9_36/Makefile.in
+++ b/dlls/d3dx9_36/Makefile.in
@@ -7,6 +7,9 @@ IMPORTLIB = d3dx9
 IMPORTS   = d3d9 gdi32 user32 kernel32
 
 C_SRCS = \
+	asmparser.c \
+	asmutils.c \
+	bytecodewriter.c \
 	core.c \
 	d3dx9_36_main.c \
 	font.c \
@@ -17,6 +20,9 @@ C_SRCS = \
 	surface.c \
 	util.c
 
+LEX_SRCS = asmshader.l
+BISON_SRCS = asmshader.y
+
 RC_SRCS = version.rc
 
 @MAKE_DLL_RULES@
diff --git a/dlls/d3dx9_36/asmparser.c b/dlls/d3dx9_36/asmparser.c
new file mode 100644
index 0000000..a880b62
--- /dev/null
+++ b/dlls/d3dx9_36/asmparser.c
@@ -0,0 +1,156 @@
+/*
+ * Direct3D asm shader parser
+ *
+ * Copyright 2008 Stefan Dösinger
+ * Copyright 2009 Matteo Bruni
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ *
+ */
+
+#include "config.h"
+#include "wine/port.h"
+#include "wine/debug.h"
+
+#include "d3dx9_36_private.h"
+
+WINE_DEFAULT_DEBUG_CHANNEL(asmshader);
+WINE_DECLARE_DEBUG_CHANNEL(parsed_shader);
+
+
+/****************************************************************
+ * Common(non-version specific) shader parser control code      *
+ ****************************************************************/
+
+static void asmparser_end(struct asm_parser *This) {
+    TRACE("Finalizing shader\n");
+}
+
+static void asmparser_constF(struct asm_parser *This, DWORD reg, float x, float y, float z, float w) {
+    if(!This->shader) return;
+    TRACE("Adding float constant %u at pos %u\n", reg, This->shader->num_cf);
+    TRACE_(parsed_shader)("def c%u, %f, %f, %f, %f\n", reg, x, y, z, w);
+    if(!add_constF(This->shader, reg, x, y, z, w)) {
+        ERR("Out of memory\n");
+        set_parse_status(This, PARSE_ERR);
+    }
+}
+
+static void asmparser_constB(struct asm_parser *This, DWORD reg, BOOL x) {
+    if(!This->shader) return;
+    TRACE("Adding boolean constant %u at pos %u\n", reg, This->shader->num_cb);
+    TRACE_(parsed_shader)("def b%u, %s\n", reg, x ? "true" : "false");
+    if(!add_constB(This->shader, reg, x)) {
+        ERR("Out of memory\n");
+        set_parse_status(This, PARSE_ERR);
+    }
+}
+
+static void asmparser_constI(struct asm_parser *This, DWORD reg, INT x, INT y, INT z, INT w) {
+    if(!This->shader) return;
+    TRACE("Adding integer constant %u at pos %u\n", reg, This->shader->num_ci);
+    TRACE_(parsed_shader)("def i%u, %d, %d, %d, %d\n", reg, x, y, z, w);
+    if(!add_constI(This->shader, reg, x, y, z, w)) {
+        ERR("Out of memory\n");
+        set_parse_status(This, PARSE_ERR);
+    }
+}
+
+static void asmparser_dcl_output(struct asm_parser *This, DWORD usage, DWORD num,
+                                 const struct shader_reg *reg) {
+    if(!This->shader) return;
+    if(This->shader->type == ST_PIXEL) {
+        asmparser_message(This, "Line %u: Output register declared in a pixel shader\n", This->line_no);
+        set_parse_status(This, PARSE_ERR);
+    }
+    if(!record_declaration(This->shader, usage, num, TRUE, reg->regnum, reg->writemask)) {
+        ERR("Out of memory\n");
+        set_parse_status(This, PARSE_ERR);
+    }
+}
+
+static void asmparser_dcl_input(struct asm_parser *This, DWORD usage, DWORD num,
+                                const struct shader_reg *reg) {
+    if(!This->shader) return;
+    if(!record_declaration(This->shader, usage, num, FALSE, reg->regnum, reg->writemask)) {
+        ERR("Out of memory\n");
+        set_parse_status(This, PARSE_ERR);
+    }
+}
+
+static void asmparser_dcl_sampler(struct asm_parser *This, DWORD samptype, DWORD regnum, unsigned int line_no) {
+    if(!This->shader) return;
+    if(!record_sampler(This->shader, samptype, regnum, line_no)) {
+        ERR("Out of memory\n");
+        set_parse_status(This, PARSE_ERR);
+    }
+}
+
+static void asmparser_instr(struct asm_parser *This, DWORD opcode,
+                            DWORD mod, DWORD shift,
+                            BWRITER_COMPARISON_TYPE comp,
+                            const struct shader_reg *dst,
+                            const struct src_regs *srcs, int expectednsrcs) {
+    struct instruction *instr;
+    unsigned int i;
+    BOOL firstreg = TRUE;
+    unsigned int src_count = srcs ? srcs->count : 0;
+
+    if(!This->shader) return;
+
+    TRACE_(parsed_shader)("%s%s%s%s ", debug_print_opcode(opcode),
+                          debug_print_dstmod(mod),
+                          debug_print_shift(shift),
+                          debug_print_comp(comp));
+    if(dst) {
+        TRACE_(parsed_shader)("%s", debug_print_dstreg(dst, This->shader->type));
+        firstreg = FALSE;
+    }
+    for(i = 0; i < src_count; i++) {
+        if(!firstreg) TRACE_(parsed_shader)(", ");
+        else firstreg = FALSE;
+        TRACE_(parsed_shader)("%s", debug_print_srcreg(&srcs->reg[i],
+                                                       This->shader->type));
+    }
+    TRACE_(parsed_shader)("\n");
+
+    if(src_count != expectednsrcs) {
+        asmparser_message(This, "Line %u: Wrong number of source registers\n", This->line_no);
+        set_parse_status(This, PARSE_ERR);
+        return;
+    }
+
+    instr = alloc_instr(src_count);
+    if(!instr) {
+        ERR("Error allocating memory for the instruction\n");
+        set_parse_status(This, PARSE_ERR);
+        return;
+    }
+
+    instr->opcode = opcode;
+    instr->dstmod = mod;
+    instr->shift = shift;
+    instr->comptype = comp;
+    if(dst) This->funcs->dstreg(This, instr, dst);
+    for(i = 0; i < src_count; i++) {
+        This->funcs->srcreg(This, instr, i, &srcs->reg[i]);
+    }
+
+    if(!add_instruction(This->shader, instr)) {
+        ERR("Out of memory\n");
+        set_parse_status(This, PARSE_ERR);
+    }
+}
+
diff --git a/dlls/d3dx9_36/asmshader.l b/dlls/d3dx9_36/asmshader.l
new file mode 100644
index 0000000..824cdbc
--- /dev/null
+++ b/dlls/d3dx9_36/asmshader.l
@@ -0,0 +1,552 @@
+/*
+ * Direct3D shader assembler
+ *
+ * Copyright 2008 Stefan Dösinger
+ * Copyright 2009 Matteo Bruni
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+%{
+#include "config.h"
+#include "wine/port.h"
+#include "wine/debug.h"
+
+#include "d3dx9_36_private.h"
+#include "asmshader.tab.h"
+
+WINE_DEFAULT_DEBUG_CHANNEL(asmshader);
+%}
+
+%option reentrant bison-bridge
+%option noyywrap
+%option prefix="asmshader_"
+%option noinput nounput
+
+/* Swizzles and writemasks consist of a dot and up to 4 x, y, z or w characters,
+ * or up to 4 a, r, g, b characters. There are different rules for swizzles and
+ * writemasks wrt repetition, those are handled in the grammar. color(argb) and
+ * coordinate(xyzw) components cannot be mixed.
+ */
+SWIZZLE                 \.(([w-z]+)|((a|r|g|b)+))
+
+/* Registers */
+REG_TEMP                r[0-9]+
+/* for relative addressing in the form o[x], v[x] and c[x] */
+REG_OUTPUT              o[0-9]*
+REG_INPUT               v[0-9]*
+REG_CONSTFLOAT          c[0-9]*
+REG_CONSTINT            i[0-9]+
+REG_CONSTBOOL           b[0-9]+
+REG_TEXTURE             t[0-9]+
+REG_TEXCRDOUT           oT[0-9]+
+REG_SAMPLER             s[0-9]+
+REG_OPOS                oPos
+REG_OFOG                oFog
+REG_OPTS                oPts
+REG_VERTEXCOLOR         oD0|oD1
+REG_FRAGCOLOR           oC[0-9]+
+REG_FRAGDEPTH           oDepth
+REG_VPOS                vPos
+REG_VFACE               vFace
+REG_ADDRESS             a0
+REG_LOOP                aL
+REG_PREDICATE           p0
+/* Not really a register, but it is considered as such */
+REG_LABEL               l[0-9]+
+
+DCL_POSITION            _position[0-9]*
+DCL_BLENDWEIGHT         _blendweight[0-9]*
+DCL_BLENDINDICES        _blendindices[0-9]*
+DCL_NORMAL              _normal[0-9]*
+DCL_PSIZE               _psize[0-9]*
+DCL_TEXCOORD            _texcoord[0-9]*
+DCL_TANGENT             _tangent[0-9]*
+DCL_BINORMAL            _binormal[0-9]*
+DCL_TESSFACTOR          _tessfactor[0-9]*
+DCL_POSITIONT           _positiont[0-9]*
+DCL_COLOR               _color[0-9]*
+DCL_FOG                 _fog[0-9]*
+DCL_DEPTH               _depth[0-9]*
+DCL_SAMPLE              _sample[0-9]*
+
+DCL_SAMPLER1D           _1d
+DCL_SAMPLER2D           _2d
+DCL_SAMPLERCUBE         _cube
+DCL_SAMPLERVOLUME       _volume
+
+PREPROCESSORDIRECTIVE   #[^\n]*\n
+
+/* Comments */
+DOUBLESLASHCOMMENT      "//"[^\n]*
+SEMICOLONCOMMENT        ";"[^\n]*
+
+/* Whitespaces are spaces, tabs and newlines */
+WHITESPACE              [ \t]+
+NEWLINE                 (\n)|(\r\n)
+
+COMMA                   ","
+
+IMMVAL                  \-?(([0-9]+)|([0-9]*\.[0-9]+))(f)?
+
+ANY                     (.)
+
+%%
+
+    /* Common instructions(vertex and pixel shaders) */
+add                     {return INSTR_ADD;          }
+nop                     {return INSTR_NOP;          }
+mov                     {return INSTR_MOV;          }
+sub                     {return INSTR_SUB;          }
+mad                     {return INSTR_MAD;          }
+mul                     {return INSTR_MUL;          }
+rcp                     {return INSTR_RCP;          }
+rsq                     {return INSTR_RSQ;          }
+dp3                     {return INSTR_DP3;          }
+dp4                     {return INSTR_DP4;          }
+min                     {return INSTR_MIN;          }
+max                     {return INSTR_MAX;          }
+slt                     {return INSTR_SLT;          }
+sge                     {return INSTR_SGE;          }
+abs                     {return INSTR_ABS;          }
+exp                     {return INSTR_EXP;          }
+log                     {return INSTR_LOG;          }
+expp                    {return INSTR_EXPP;         }
+logp                    {return INSTR_LOGP;         }
+dst                     {return INSTR_DST;          }
+lrp                     {return INSTR_LRP;          }
+frc                     {return INSTR_FRC;          }
+pow                     {return INSTR_POW;          }
+crs                     {return INSTR_CRS;          }
+sgn                     {return INSTR_SGN;          }
+nrm                     {return INSTR_NRM;          }
+sincos                  {return INSTR_SINCOS;       }
+m4x4                    {return INSTR_M4x4;         }
+m4x3                    {return INSTR_M4x3;         }
+m3x4                    {return INSTR_M3x4;         }
+m3x3                    {return INSTR_M3x3;         }
+m3x2                    {return INSTR_M3x2;         }
+dcl                     {return INSTR_DCL;          }
+def                     {return INSTR_DEF;          }
+defb                    {return INSTR_DEFB;         }
+defi                    {return INSTR_DEFI;         }
+rep                     {return INSTR_REP;          }
+endrep                  {return INSTR_ENDREP;       }
+if                      {return INSTR_IF;           }
+else                    {return INSTR_ELSE;         }
+endif                   {return INSTR_ENDIF;        }
+break                   {return INSTR_BREAK;        }
+breakp                  {return INSTR_BREAKP;       }
+call                    {return INSTR_CALL;         }
+callnz                  {return INSTR_CALLNZ;       }
+loop                    {return INSTR_LOOP;         }
+ret                     {return INSTR_RET;          }
+endloop                 {return INSTR_ENDLOOP;      }
+label                   {return INSTR_LABEL;        }
+setp                    {return INSTR_SETP;         }
+texldl                  {return INSTR_TEXLDL;       }
+
+    /* Vertex shader only instructions  */
+lit                     {return INSTR_LIT;          }
+mova                    {return INSTR_MOVA;         }
+
+    /* Pixel shader only instructions   */
+cnd                     {return INSTR_CND;          }
+cmp                     {return INSTR_CMP;          }
+dp2add                  {return INSTR_DP2ADD;       }
+texcoord                {return INSTR_TEXCOORD;     }
+texcrd                  {return INSTR_TEXCRD;       }
+texkill                 {return INSTR_TEXKILL;      }
+tex                     {return INSTR_TEX;          }
+texld                   {return INSTR_TEXLD;        }
+texbem                  {return INSTR_TEXBEM;       }
+texbeml                 {return INSTR_TEXBEML;      }
+texreg2ar               {return INSTR_TEXREG2AR;    }
+texreg2gb               {return INSTR_TEXREG2GB;    }
+texreg2rgb              {return INSTR_TEXREG2RGB;   }
+texm3x2pad              {return INSTR_TEXM3x2PAD;   }
+texm3x2tex              {return INSTR_TEXM3x2TEX;   }
+texm3x3pad              {return INSTR_TEXM3x3PAD;   }
+texm3x3diff             {return INSTR_TEXM3x3DIFF;  }
+texm3x3spec             {return INSTR_TEXM3x3SPEC;  }
+texm3x3vspec            {return INSTR_TEXM3x3VSPEC; }
+texm3x3tex              {return INSTR_TEXM3x3TEX;   }
+texdp3tex               {return INSTR_TEXDP3TEX;    }
+texm3x2depth            {return INSTR_TEXM3x2DEPTH; }
+texdp3                  {return INSTR_TEXDP3;       }
+texm3x3                 {return INSTR_TEXM3x3;      }
+texdepth                {return INSTR_TEXDEPTH;     }
+bem                     {return INSTR_BEM;          }
+dsx                     {return INSTR_DSX;          }
+dsy                     {return INSTR_DSY;          }
+texldp                  {return INSTR_TEXLDP;       }
+texldb                  {return INSTR_TEXLDB;       }
+texldd                  {return INSTR_TEXLDD;       }
+phase                   {return INSTR_PHASE;        }
+
+{REG_TEMP}              {
+                            yylval->regnum = atoi(yytext + 1);
+                            return REG_TEMP;
+                        }
+{REG_OUTPUT}            {
+                            yylval->regnum = atoi(yytext + 1);
+                            return REG_OUTPUT;
+                        }
+{REG_INPUT}             {
+                            yylval->regnum = atoi(yytext + 1);
+                            return REG_INPUT;
+                        }
+{REG_CONSTFLOAT}        {
+                            yylval->regnum = atoi(yytext + 1);
+                            return REG_CONSTFLOAT;
+                        }
+{REG_CONSTINT}          {
+                            yylval->regnum = atoi(yytext + 1);
+                            return REG_CONSTINT;
+                        }
+{REG_CONSTBOOL}         {
+                            yylval->regnum = atoi(yytext + 1);
+                            return REG_CONSTBOOL;
+                        }
+{REG_TEXTURE}           {
+                            yylval->regnum = atoi(yytext + 1);
+                            return REG_TEXTURE;
+                        }
+{REG_TEXCRDOUT}         {
+                            yylval->regnum = atoi(yytext + 2);
+                            return REG_TEXCRDOUT;
+                        }
+{REG_SAMPLER}           {
+                            yylval->regnum = atoi(yytext + 1);
+                            return REG_SAMPLER;
+                        }
+{REG_OPOS}              {return REG_OPOS;           }
+{REG_OFOG}              {return REG_OFOG;           }
+{REG_OPTS}              {return REG_OPTS;           }
+{REG_VERTEXCOLOR}       {
+                            yylval->regnum = atoi(yytext + 2);
+                            return REG_VERTEXCOLOR;
+                        }
+{REG_FRAGCOLOR}         {
+                            yylval->regnum = atoi(yytext + 2);
+                            return REG_FRAGCOLOR;
+                        }
+{REG_FRAGDEPTH}         {
+                            return REG_FRAGDEPTH;
+                        }
+{REG_VPOS}              {return REG_VPOS;           }
+{REG_VFACE}             {return REG_VFACE;          }
+{REG_ADDRESS}           {return REG_ADDRESS;        }
+{REG_LOOP}              {return REG_LOOP;           }
+{REG_PREDICATE}         {return REG_PREDICATE;      }
+
+{REG_LABEL}             {
+                            yylval->regnum = atoi(yytext + 1);
+                            return REG_LABEL;
+                        }
+
+    /* Shader versions. These are important to select the correct
+     * parser profile.
+     */
+vs\.1\.0|vs_1_0         {return VER_VS10;       }
+vs\.1\.1|vs_1_1         {return VER_VS11;       }
+
+vs_2_0                  {return VER_VS20;       }
+vs_2_x                  {return VER_VS2X;       }
+vs_3_0                  {return VER_VS30;       }
+
+ps\.1\.0|ps_1_0         {return VER_PS10;       }
+ps\.1\.1|ps_1_1         {return VER_PS11;       }
+ps\.1\.2|ps_1_2         {return VER_PS12;       }
+ps\.1\.3|ps_1_3         {return VER_PS13;       }
+ps\.1\.4|ps_1_4         {return VER_PS14;       }
+
+ps_2_0                  {return VER_PS20;       }
+ps_2_x                  {return VER_PS2X;       }
+ps_3_0                  {return VER_PS30;       }
+
+{SWIZZLE}               {
+                            unsigned char i;
+                            char last = 0;
+                            DWORD ret = 0;
+                            BOOL wmask_valid = TRUE;
+
+                            yylval->swizzle_wmask.swizzle = text2swizzle(yytext + 1);
+                            if(yylval->swizzle_wmask.swizzle == SWIZZLE_ERR) {
+                                TRACE("Invalid swizzle/writemask %s\n", yytext);
+                                yylval->swizzle_wmask.writemask = 0;
+                                return SWIZZLE;
+                            }
+                            ret = 0;
+                            last = 0;
+                            for(i = 0; i < strlen(yytext + 1); i++) {
+                                switch(yytext[i + 1]) {
+                                    case 'x':   case 'X':
+                                    case 'r':   case 'R':
+                                        if(last == 'x' || last == 'y' || last == 'z' || last == 'w') {
+                                            wmask_valid = FALSE;
+                                            break;
+                                        }
+                                        ret |= BWRITERSP_WRITEMASK_0;
+                                        last = 'x';
+                                        break;
+                                    case 'y':   case 'Y':
+                                    case 'g':   case 'G':
+                                        if(last == 'y' || last == 'z' || last == 'w') {
+                                            wmask_valid = FALSE;
+                                            break;
+                                        }
+                                        ret |= BWRITERSP_WRITEMASK_1;
+                                        last = 'y';
+                                        break;
+                                    case 'z':   case 'Z':
+                                    case 'b':   case 'B':
+                                        if(last == 'z' || last == 'w') {
+                                            wmask_valid = FALSE;
+                                            break;
+                                        }
+                                        ret |= BWRITERSP_WRITEMASK_2;
+                                        last = 'z';
+                                        break;
+                                    case 'w':   case 'W':
+                                    case 'a':   case 'A':
+                                        if(last == 'w') {
+                                            wmask_valid = FALSE;
+                                            break;
+                                        }
+                                        ret |= BWRITERSP_WRITEMASK_3;
+                                        last = 'w';
+                                        break;
+                                }
+                            }
+                            if(wmask_valid) {
+                                TRACE("Swizzle/Writemask string is a valid writemask\n");
+                                yylval->swizzle_wmask.writemask = ret;
+                            } else {
+                                TRACE("Swizzle/Writemask string is not a valid writemask\n");
+                                yylval->swizzle_wmask.writemask = 0;
+                            }
+                            return SWIZZLE;
+                        }
+
+    /* Output modifiers */
+\_x2                    {return SHIFT_X2;           }
+\_x4                    {return SHIFT_X4;           }
+\_x8                    {return SHIFT_X8;           }
+\_d2                    {return SHIFT_D2;           }
+\_d4                    {return SHIFT_D4;           }
+\_d8                    {return SHIFT_D8;           }
+\_sat                   {return MOD_SAT;            }
+\_pp                    {return MOD_PP;             }
+\_centroid              {return MOD_CENTROID;       }
+
+    /* compare params */
+\_gt                    {return COMP_GT;            }
+\_lt                    {return COMP_LT;            }
+\_ge                    {return COMP_GE;            }
+\_le                    {return COMP_LE;            }
+\_eq                    {return COMP_EQ;            }
+\_ne                    {return COMP_NE;            }
+
+{IMMVAL}                {
+                            yylval->immval.val = atof(yytext);
+                            yylval->immval.integer = ((strstr(yytext, ".") == NULL) && (strstr(yytext, "f") == NULL));
+                            return IMMVAL;
+                        }
+true                    {
+                            yylval->immbool = TRUE;
+                            return MYBOOL;
+                        }
+false                   {
+                            yylval->immbool = FALSE;
+                            return MYBOOL;
+                        }
+
+{COMMA}                 {return yytext[0];          }
+-                       {return yytext[0];          }
+\(                      {return yytext[0];          }
+\)                      {return yytext[0];          }
+
+    /* for relative addressing */
+\[|\]|\+                {return yytext[0];          }
+
+\_bias                  {return SMOD_BIAS;          }
+    /* No _x2 here; it is identical to MOD_X2 */
+\_bx2                   {return SMOD_SCALEBIAS;     }
+\_dz                    {return SMOD_DZ;            }
+\_dw                    {return SMOD_DW;            }
+\_abs                   {return SMOD_ABS;           }
+
+!                       {return SMOD_NOT;           }
+
+{DCL_POSITION}          {
+                            if(yytext[strlen("_position")] == '\0') {
+                                yylval->regnum = 0;
+                            } else {
+                                yylval->regnum = atoi(yytext + strlen("_position"));
+                            }
+                            return USAGE_POSITION;
+                        }
+{DCL_BLENDWEIGHT}       {
+                            if(yytext[strlen("_blendweight")] == '\0') {
+                                yylval->regnum = 0;
+                            } else {
+                                yylval->regnum = atoi(yytext + strlen("_blendweight"));
+                            }
+                            return USAGE_BLENDWEIGHT;
+                        }
+{DCL_BLENDINDICES}      {
+                            if(yytext[strlen("_blendindices")] == '\0') {
+                                yylval->regnum = 0;
+                            } else {
+                                yylval->regnum = atoi(yytext + strlen("_blendindices"));
+                            }
+                            return USAGE_BLENDINDICES;
+                        }
+{DCL_NORMAL}            {
+                            if(yytext[strlen("_normal")] == '\0') {
+                                yylval->regnum = 0;
+                            } else {
+                                yylval->regnum = atoi(yytext + strlen("_normal"));
+                            }
+                            return USAGE_NORMAL;
+                        }
+{DCL_PSIZE}             {
+                            if(yytext[strlen("_psize")] == '\0') {
+                                yylval->regnum = 0;
+                            } else {
+                                yylval->regnum = atoi(yytext + strlen("_psize"));
+                            }
+                            return USAGE_PSIZE;
+                        }
+{DCL_TEXCOORD}          {
+                            if(yytext[strlen("_texcoord")] == '\0') {
+                                yylval->regnum = 0;
+                            } else {
+                                yylval->regnum = atoi(yytext + strlen("_texcoord"));
+                            }
+                            return USAGE_TEXCOORD;
+                        }
+{DCL_TANGENT}           {
+                            if(yytext[strlen("_tangent")] == '\0') {
+                                yylval->regnum = 0;
+                            } else {
+                                yylval->regnum = atoi(yytext + strlen("_tangent"));
+                            }
+                            return USAGE_TANGENT;
+                        }
+{DCL_BINORMAL}          {
+                            if(yytext[strlen("_binormal")] == '\0') {
+                                yylval->regnum = 0;
+                            } else {
+                                yylval->regnum = atoi(yytext + strlen("_binormal"));
+                            }
+                            return USAGE_BINORMAL;
+                        }
+{DCL_TESSFACTOR}        {
+                            if(yytext[strlen("_tessfactor")] == '\0') {
+                                yylval->regnum = 0;
+                            } else {
+                                yylval->regnum = atoi(yytext + strlen("_tessfactor"));
+                            }
+                            return USAGE_TESSFACTOR;
+                        }
+{DCL_POSITIONT}         {
+                            if(yytext[strlen("_positiont")] == '\0') {
+                                yylval->regnum = 0;
+                            } else {
+                                yylval->regnum = atoi(yytext + strlen("_positiont"));
+                            }
+                            return USAGE_POSITIONT;
+                        }
+{DCL_COLOR}             {
+                            if(yytext[strlen("_color")] == '\0') {
+                                yylval->regnum = 0;
+                            } else {
+                                yylval->regnum = atoi(yytext + strlen("_color"));
+                            }
+                            return USAGE_COLOR;
+                        }
+{DCL_FOG}               {
+                            if(yytext[strlen("_fog")] == '\0') {
+                                yylval->regnum = 0;
+                            } else {
+                                yylval->regnum = atoi(yytext + strlen("_fog"));
+                            }
+                            return USAGE_FOG;
+                        }
+{DCL_DEPTH}             {
+                            if(yytext[strlen("_depth")] == '\0') {
+                                yylval->regnum = 0;
+                            } else {
+                                yylval->regnum = atoi(yytext + strlen("_depth"));
+                            }
+                            return USAGE_DEPTH;
+                        }
+{DCL_SAMPLE}            {
+                            if(yytext[strlen("_sample")] == '\0') {
+                                yylval->regnum = 0;
+                            } else {
+                                yylval->regnum = atoi(yytext + strlen("_sample"));
+                            }
+                            return USAGE_SAMPLE;
+                        }
+
+{DCL_SAMPLER1D}         { return SAMPTYPE_1D;       }
+{DCL_SAMPLER2D}         { return SAMPTYPE_2D;       }
+{DCL_SAMPLERCUBE}       { return SAMPTYPE_CUBE;     }
+{DCL_SAMPLERVOLUME}     { return SAMPTYPE_VOLUME;   }
+
+{PREPROCESSORDIRECTIVE} {
+                            /* TODO: update current line information */
+                            TRACE("line info update: %s", yytext);
+                        }
+
+    /* Skip comments */
+{DOUBLESLASHCOMMENT}    {                           }
+{SEMICOLONCOMMENT}      {                           }
+
+{WHITESPACE}            { /* Do nothing */          }
+{NEWLINE}               {
+                            struct asm_parser *ctx = yyget_extra(yyscanner);
+                            ctx->line_no++;
+                        }
+
+{ANY}                   {
+                            struct asm_parser *ctx = yyget_extra(yyscanner);
+                            asmparser_message(ctx, "Line %u: Unexpected input %s\n", ctx->line_no, yytext);
+                            set_parse_status(ctx, PARSE_ERR);
+                        }
+
+%%
+
+struct bwriter_shader *SlAssembleShader(const char *text, char **messages) {
+    struct asm_parser asm_ctx;
+    struct bwriter_shader *ret = NULL;
+    YY_BUFFER_STATE buffer;
+    TRACE("%p, %p\n", text, messages);
+
+    asmshader_lex_init(&asm_ctx.yyscanner);
+    asmshader_set_extra(&asm_ctx, asm_ctx.yyscanner);
+    buffer = asmshader__scan_string(text, asm_ctx.yyscanner);
+    asmshader__switch_to_buffer(buffer, asm_ctx.yyscanner);
+
+    ret = parse_asm_shader(&asm_ctx, messages);
+
+    asmshader__delete_buffer(buffer, asm_ctx.yyscanner);
+    asmshader_lex_destroy(asm_ctx.yyscanner);
+
+    return ret;
+}
diff --git a/dlls/d3dx9_36/asmshader.y b/dlls/d3dx9_36/asmshader.y
new file mode 100644
index 0000000..6e2f78e
--- /dev/null
+++ b/dlls/d3dx9_36/asmshader.y
@@ -0,0 +1,1606 @@
+/*
+ * Direct3D shader assembler
+ *
+ * Copyright 2008 Stefan Dösinger
+ * Copyright 2009 Matteo Bruni
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+%{
+#include "config.h"
+#include "wine/port.h"
+#include "wine/debug.h"
+
+#include "d3dx9_36_private.h"
+#include "asmshader.tab.h"
+
+#include <stdio.h>
+
+WINE_DEFAULT_DEBUG_CHANNEL(asmshader);
+
+/* Needed lexer functions declarations */
+void asmshader_error (struct asm_parser *ctx, void *scanner, char const *s);
+int asmshader_lex (YYSTYPE * yylval_param, void *scanner);
+
+void set_rel_reg(struct shader_reg *reg, struct rel_reg *rel) {
+    /* We can have an additional offset without true relative addressing
+     * ex. c2[ 4 ] */
+    reg->regnum += rel->additional_offset;
+    if(!rel->has_rel_reg) {
+        reg->rel_reg = NULL;
+    } else {
+        reg->rel_reg = asm_alloc(sizeof(*reg->rel_reg));
+        if(!reg->rel_reg) {
+            return;
+        }
+        reg->rel_reg->type = rel->type;
+        reg->rel_reg->swizzle = rel->swizzle;
+        reg->rel_reg->regnum = rel->rel_regnum;
+    }
+}
+
+%}
+
+%pure-parser
+%parse-param{struct asm_parser *ctx}
+%parse-param{void *scanner}
+%lex-param{yyscan_t *scanner}
+
+%union {
+    struct {
+        float           val;
+        BOOL            integer;
+    } immval;
+    BOOL                immbool;
+    unsigned int        regnum;
+    struct shader_reg   reg;
+    DWORD               srcmod;
+    struct {
+        DWORD           swizzle;
+        DWORD           writemask;
+    } swizzle_wmask;
+    DWORD               writemask;
+    DWORD               swizzle;
+    struct {
+        DWORD           mod;
+        DWORD           shift;
+    } modshift;
+    BWRITER_COMPARISON_TYPE comptype;
+    struct {
+        DWORD           dclusage;
+        unsigned int    regnum;
+    } declaration;
+    BWRITERSAMPLER_TEXTURE_TYPE samplertype;
+    struct rel_reg      rel_reg;
+    struct src_regs     sregs;
+}
+
+/* Common instructions between vertex and pixel shaders */
+%token INSTR_ADD
+%token INSTR_NOP
+%token INSTR_MOV
+%token INSTR_SUB
+%token INSTR_MAD
+%token INSTR_MUL
+%token INSTR_RCP
+%token INSTR_RSQ
+%token INSTR_DP3
+%token INSTR_DP4
+%token INSTR_MIN
+%token INSTR_MAX
+%token INSTR_SLT
+%token INSTR_SGE
+%token INSTR_ABS
+%token INSTR_EXP
+%token INSTR_LOG
+%token INSTR_EXPP
+%token INSTR_LOGP
+%token INSTR_DST
+%token INSTR_LRP
+%token INSTR_FRC
+%token INSTR_POW
+%token INSTR_CRS
+%token INSTR_SGN
+%token INSTR_NRM
+%token INSTR_SINCOS
+%token INSTR_M4x4
+%token INSTR_M4x3
+%token INSTR_M3x4
+%token INSTR_M3x3
+%token INSTR_M3x2
+%token INSTR_DCL
+%token INSTR_DEF
+%token INSTR_DEFB
+%token INSTR_DEFI
+%token INSTR_REP
+%token INSTR_ENDREP
+%token INSTR_IF
+%token INSTR_ELSE
+%token INSTR_ENDIF
+%token INSTR_BREAK
+%token INSTR_BREAKP
+%token INSTR_CALL
+%token INSTR_CALLNZ
+%token INSTR_LOOP
+%token INSTR_RET
+%token INSTR_ENDLOOP
+%token INSTR_LABEL
+%token INSTR_SETP
+%token INSTR_TEXLDL
+
+/* Vertex shader only instructions  */
+%token INSTR_LIT
+%token INSTR_MOVA
+
+/* Pixel shader only instructions   */
+%token INSTR_CND
+%token INSTR_CMP
+%token INSTR_DP2ADD
+%token INSTR_TEXCOORD
+%token INSTR_TEXCRD
+%token INSTR_TEXKILL
+%token INSTR_TEX
+%token INSTR_TEXLD
+%token INSTR_TEXBEM
+%token INSTR_TEXBEML
+%token INSTR_TEXREG2AR
+%token INSTR_TEXREG2GB
+%token INSTR_TEXREG2RGB
+%token INSTR_TEXM3x2PAD
+%token INSTR_TEXM3x2TEX
+%token INSTR_TEXM3x3PAD
+%token INSTR_TEXM3x3DIFF
+%token INSTR_TEXM3x3SPEC
+%token INSTR_TEXM3x3VSPEC
+%token INSTR_TEXM3x3TEX
+%token INSTR_TEXDP3TEX
+%token INSTR_TEXM3x2DEPTH
+%token INSTR_TEXDP3
+%token INSTR_TEXM3x3
+%token INSTR_TEXDEPTH
+%token INSTR_BEM
+%token INSTR_DSX
+%token INSTR_DSY
+%token INSTR_TEXLDP
+%token INSTR_TEXLDB
+%token INSTR_TEXLDD
+%token INSTR_PHASE
+
+/* Registers */
+%token <regnum> REG_TEMP
+%token <regnum> REG_OUTPUT
+%token <regnum> REG_INPUT
+%token <regnum> REG_CONSTFLOAT
+%token <regnum> REG_CONSTINT
+%token <regnum> REG_CONSTBOOL
+%token <regnum> REG_TEXTURE
+%token <regnum> REG_SAMPLER
+%token <regnum> REG_TEXCRDOUT
+%token REG_OPOS
+%token REG_OFOG
+%token REG_OPTS
+%token <regnum> REG_VERTEXCOLOR
+%token <regnum> REG_FRAGCOLOR
+%token REG_FRAGDEPTH
+%token REG_VPOS
+%token REG_VFACE
+%token REG_ADDRESS
+%token REG_LOOP
+%token REG_PREDICATE
+%token <regnum> REG_LABEL
+
+/* Version tokens */
+%token VER_VS10
+%token VER_VS11
+%token VER_VS20
+%token VER_VS2X
+%token VER_VS30
+
+%token VER_PS10
+%token VER_PS11
+%token VER_PS12
+%token VER_PS13
+%token VER_PS14
+%token VER_PS20
+%token VER_PS2X
+%token VER_PS30
+
+/* Output modifiers */
+%token SHIFT_X2
+%token SHIFT_X4
+%token SHIFT_X8
+%token SHIFT_D2
+%token SHIFT_D4
+%token SHIFT_D8
+%token MOD_SAT
+%token MOD_PP
+%token MOD_CENTROID
+
+/* Compare tokens */
+%token COMP_GT
+%token COMP_LT
+%token COMP_GE
+%token COMP_LE
+%token COMP_EQ
+%token COMP_NE
+
+/* Source register modifiers */
+%token SMOD_BIAS
+%token SMOD_SCALEBIAS
+%token SMOD_DZ
+%token SMOD_DW
+%token SMOD_ABS
+%token SMOD_NOT
+
+/* Sampler types */
+%token SAMPTYPE_1D
+%token SAMPTYPE_2D
+%token SAMPTYPE_CUBE
+%token SAMPTYPE_VOLUME
+
+/* Usage declaration tokens */
+%token <regnum> USAGE_POSITION
+%token <regnum> USAGE_BLENDWEIGHT
+%token <regnum> USAGE_BLENDINDICES
+%token <regnum> USAGE_NORMAL
+%token <regnum> USAGE_PSIZE
+%token <regnum> USAGE_TEXCOORD
+%token <regnum> USAGE_TANGENT
+%token <regnum> USAGE_BINORMAL
+%token <regnum> USAGE_TESSFACTOR
+%token <regnum> USAGE_POSITIONT
+%token <regnum> USAGE_COLOR
+%token <regnum> USAGE_FOG
+%token <regnum> USAGE_DEPTH
+%token <regnum> USAGE_SAMPLE
+
+/* Misc stuff */
+%token <immval> IMMVAL
+%token <immbool> MYBOOL
+%token <swizzle_wmask> SWIZZLE
+
+%type <reg> dreg_name
+%type <reg> dreg
+%type <reg> sreg_name
+%type <reg> relreg_name
+%type <reg> sreg
+%type <srcmod> smod
+%type <swizzle> swizzle
+%type <writemask> writemask
+%type <modshift> omods
+%type <modshift> omodifier
+%type <comptype> comp
+%type <declaration> dclusage
+%type <samplertype> sampdcl
+%type <rel_reg> rel_reg
+%type <reg> predicate
+%type <immval> immsum
+%type <sregs> sregs
+
+%%
+
+shader:               version_marker instructions
+                        {
+                            ctx->funcs->end(ctx);
+                        }
+
+version_marker:       VER_VS10
+                        {
+                            TRACE("Vertex shader 1.0\n");
+                            /* TODO: create the appropriate parser context */
+                        }
+                    | VER_VS11
+                        {
+                            TRACE("Vertex shader 1.1\n");
+                            /* TODO: create the appropriate parser context */
+                        }
+                    | VER_VS20
+                        {
+                            TRACE("Vertex shader 2.0\n");
+                            /* TODO: create the appropriate parser context */
+                        }
+                    | VER_VS2X
+                        {
+                            TRACE("Vertex shader 2.x\n");
+                            /* TODO: create the appropriate parser context */
+                        }
+                    | VER_VS30
+                        {
+                            TRACE("Vertex shader 3.0\n");
+                            /* TODO: create the appropriate parser context */
+                        }
+                    | VER_PS10
+                        {
+                            TRACE("Pixel  shader 1.0\n");
+                            /* TODO: create the appropriate parser context */
+                        }
+                    | VER_PS11
+                        {
+                            TRACE("Pixel  shader 1.1\n");
+                            /* TODO: create the appropriate parser context */
+                        }
+                    | VER_PS12
+                        {
+                            TRACE("Pixel  shader 1.2\n");
+                            /* TODO: create the appropriate parser context */
+                        }
+                    | VER_PS13
+                        {
+                            TRACE("Pixel  shader 1.3\n");
+                            /* TODO: create the appropriate parser context */
+                        }
+                    | VER_PS14
+                        {
+                            TRACE("Pixel  shader 1.4\n");
+                            /* TODO: create the appropriate parser context */
+                        }
+                    | VER_PS20
+                        {
+                            TRACE("Pixel  shader 2.0\n");
+                            /* TODO: create the appropriate parser context */
+                        }
+                    | VER_PS2X
+                        {
+                            TRACE("Pixel  shader 2.x\n");
+                            /* TODO: create the appropriate parser context */
+                        }
+                    | VER_PS30
+                        {
+                            TRACE("Pixel  shader 3.0\n");
+                            /* TODO: create the appropriate parser context */
+                        }
+
+instructions:         /* empty */
+                    | instructions complexinstr
+                            {
+                                /* Nothing to do */
+                            }
+
+complexinstr:         instruction
+                            {
+
+                            }
+                    | predicate instruction
+                            {
+                                TRACE("predicate\n");
+                                ctx->funcs->predicate(ctx, &$1);
+                            }
+                    | '+' instruction
+                            {
+                                TRACE("coissue\n");
+                                ctx->funcs->coissue(ctx);
+                            }
+
+instruction:          INSTR_ADD omods dreg ',' sregs
+                            {
+                                TRACE("ADD\n");
+                                ctx->funcs->instr(ctx, BWRITERSIO_ADD, $2.mod, $2.shift, 0, &$3, &$5, 2);
+                            }
+                    | INSTR_NOP
+                            {
+                                TRACE("NOP\n");
+                                ctx->funcs->instr(ctx, BWRITERSIO_NOP, 0, 0, 0, 0, 0, 0);
+                            }
+                    | INSTR_MOV omods dreg ',' sregs
+                            {
+                                TRACE("MOV\n");
+                                ctx->funcs->instr(ctx, BWRITERSIO_MOV, $2.mod, $2.shift, 0, &$3, &$5, 1);
+                            }
+                    | INSTR_SUB omods dreg ',' sregs
+                            {
+                                TRACE("SUB\n");
+                                ctx->funcs->instr(ctx, BWRITERSIO_SUB, $2.mod, $2.shift, 0, &$3, &$5, 2);
+                            }
+                    | INSTR_MAD omods dreg ',' sregs
+                            {
+                                TRACE("MAD\n");
+                                ctx->funcs->instr(ctx, BWRITERSIO_MAD, $2.mod, $2.shift, 0, &$3, &$5, 3);
+                            }
+                    | INSTR_MUL omods dreg ',' sregs
+                            {
+                                TRACE("MUL\n");
+                                ctx->funcs->instr(ctx, BWRITERSIO_MUL, $2.mod, $2.shift, 0, &$3, &$5, 2);
+                            }
+                    | INSTR_RCP omods dreg ',' sregs
+                            {
+                                TRACE("RCP\n");
+                                ctx->funcs->instr(ctx, BWRITERSIO_RCP, $2.mod, $2.shift, 0, &$3, &$5, 1);
+                            }
+                    | INSTR_RSQ omods dreg ',' sregs
+                            {
+                                TRACE("RSQ\n");
+                                ctx->funcs->instr(ctx, BWRITERSIO_RSQ, $2.mod, $2.shift, 0, &$3, &$5, 1);
+                            }
+                    | INSTR_DP3 omods dreg ',' sregs
+                            {
+                                TRACE("DP3\n");
+                                ctx->funcs->instr(ctx, BWRITERSIO_DP3, $2.mod, $2.shift, 0, &$3, &$5, 2);
+                            }
+                    | INSTR_DP4 omods dreg ',' sregs
+                            {
+                                TRACE("DP4\n");
+                                ctx->funcs->instr(ctx, BWRITERSIO_DP4, $2.mod, $2.shift, 0, &$3, &$5, 2);
+                            }
+                    | INSTR_MIN omods dreg ',' sregs
+                            {
+                                TRACE("MIN\n");
+                                ctx->funcs->instr(ctx, BWRITERSIO_MIN, $2.mod, $2.shift, 0, &$3, &$5, 2);
+                            }
+                    | INSTR_MAX omods dreg ',' sregs
+                            {
+                                TRACE("MAX\n");
+                                ctx->funcs->instr(ctx, BWRITERSIO_MAX, $2.mod, $2.shift, 0, &$3, &$5, 2);
+                            }
+                    | INSTR_SLT omods dreg ',' sregs
+                            {
+                                TRACE("SLT\n");
+                                ctx->funcs->instr(ctx, BWRITERSIO_SLT, $2.mod, $2.shift, 0, &$3, &$5, 2);
+                            }
+                    | INSTR_SGE omods dreg ',' sregs
+                            {
+                                TRACE("SGE\n");
+                                ctx->funcs->instr(ctx, BWRITERSIO_SGE, $2.mod, $2.shift, 0, &$3, &$5, 2);
+                            }
+                    | INSTR_ABS omods dreg ',' sregs
+                            {
+                                TRACE("ABS\n");
+                                ctx->funcs->instr(ctx, BWRITERSIO_ABS, $2.mod, $2.shift, 0, &$3, &$5, 1);
+                            }
+                    | INSTR_EXP omods dreg ',' sregs
+                            {
+                                TRACE("EXP\n");
+                                ctx->funcs->instr(ctx, BWRITERSIO_EXP, $2.mod, $2.shift, 0, &$3, &$5, 1);
+                            }
+                    | INSTR_LOG omods dreg ',' sregs
+                            {
+                                TRACE("LOG\n");
+                                ctx->funcs->instr(ctx, BWRITERSIO_LOG, $2.mod, $2.shift, 0, &$3, &$5, 1);
+                            }
+                    | INSTR_LOGP omods dreg ',' sregs
+                            {
+                                TRACE("LOGP\n");
+                                ctx->funcs->instr(ctx, BWRITERSIO_LOGP, $2.mod, $2.shift, 0, &$3, &$5, 1);
+                            }
+                    | INSTR_EXPP omods dreg ',' sregs
+                            {
+                                TRACE("EXPP\n");
+                                ctx->funcs->instr(ctx, BWRITERSIO_EXPP, $2.mod, $2.shift, 0, &$3, &$5, 1);
+                            }
+                    | INSTR_DST omods dreg ',' sregs
+                            {
+                                TRACE("DST\n");
+                                ctx->funcs->instr(ctx, BWRITERSIO_DST, $2.mod, $2.shift, 0, &$3, &$5, 2);
+                            }
+                    | INSTR_LRP omods dreg ',' sregs
+                            {
+                                TRACE("LRP\n");
+                                ctx->funcs->instr(ctx, BWRITERSIO_LRP, $2.mod, $2.shift, 0, &$3, &$5, 3);
+                            }
+                    | INSTR_FRC omods dreg ',' sregs
+                            {
+                                TRACE("FRC\n");
+                                ctx->funcs->instr(ctx, BWRITERSIO_FRC, $2.mod, $2.shift, 0, &$3, &$5, 1);
+                            }
+                    | INSTR_POW omods dreg ',' sregs
+                            {
+                                TRACE("POW\n");
+                                ctx->funcs->instr(ctx, BWRITERSIO_POW, $2.mod, $2.shift, 0, &$3, &$5, 2);
+                            }
+                    | INSTR_CRS omods dreg ',' sregs
+                            {
+                                TRACE("CRS\n");
+                                ctx->funcs->instr(ctx, BWRITERSIO_CRS, $2.mod, $2.shift, 0, &$3, &$5, 2);
+                            }
+                    | INSTR_SGN omods dreg ',' sregs
+                            {
+                                TRACE("SGN\n");
+                                ctx->funcs->instr(ctx, BWRITERSIO_SGN, $2.mod, $2.shift, 0, &$3, &$5, 3);
+                            }
+                    | INSTR_NRM omods dreg ',' sregs
+                            {
+                                TRACE("NRM\n");
+                                ctx->funcs->instr(ctx, BWRITERSIO_NRM, $2.mod, $2.shift, 0, &$3, &$5, 1);
+                            }
+                    | INSTR_SINCOS omods dreg ',' sregs
+                            {
+                                TRACE("SINCOS\n");
+                                ctx->funcs->instr(ctx, BWRITERSIO_SINCOS, $2.mod, $2.shift, 0, &$3, &$5, 3);
+                            }
+                    | INSTR_M4x4 omods dreg ',' sregs
+                            {
+                                TRACE("M4x4\n");
+                                ctx->funcs->instr(ctx, BWRITERSIO_M4x4, $2.mod, $2.shift, 0, &$3, &$5, 2);
+                            }
+                    | INSTR_M4x3 omods dreg ',' sregs
+                            {
+                                TRACE("M4x3\n");
+                                ctx->funcs->instr(ctx, BWRITERSIO_M4x3, $2.mod, $2.shift, 0, &$3, &$5, 2);
+                            }
+                    | INSTR_M3x4 omods dreg ',' sregs
+                            {
+                                TRACE("M3x4\n");
+                                ctx->funcs->instr(ctx, BWRITERSIO_M3x4, $2.mod, $2.shift, 0, &$3, &$5, 2);
+                            }
+                    | INSTR_M3x3 omods dreg ',' sregs
+                            {
+                                TRACE("M3x3\n");
+                                ctx->funcs->instr(ctx, BWRITERSIO_M3x3, $2.mod, $2.shift, 0, &$3, &$5, 2);
+                            }
+                    | INSTR_M3x2 omods dreg ',' sregs
+                            {
+                                TRACE("M3x2\n");
+                                ctx->funcs->instr(ctx, BWRITERSIO_M3x2, $2.mod, $2.shift, 0, &$3, &$5, 2);
+                            }
+                    | INSTR_DCL dclusage REG_OUTPUT
+                            {
+                                struct shader_reg reg;
+                                TRACE("Output reg declaration\n");
+                                memset(&reg, 0, sizeof(reg));
+                                reg.type = BWRITERSPR_OUTPUT;
+                                reg.regnum = $3;
+                                reg.rel_reg = NULL;
+                                reg.srcmod = 0;
+                                reg.writemask = BWRITERSP_WRITEMASK_ALL;
+                                ctx->funcs->dcl_output(ctx, $2.dclusage, $2.regnum, &reg);
+                            }
+                    | INSTR_DCL dclusage REG_OUTPUT writemask
+                            {
+                                struct shader_reg reg;
+                                TRACE("Output reg declaration\n");
+                                memset(&reg, 0, sizeof(reg));
+                                reg.type = BWRITERSPR_OUTPUT;
+                                reg.regnum = $3;
+                                reg.rel_reg = NULL;
+                                reg.srcmod = 0;
+                                reg.writemask = $4;
+                                ctx->funcs->dcl_output(ctx, $2.dclusage, $2.regnum, &reg);
+                            }
+                    | INSTR_DCL dclusage REG_INPUT
+                            {
+                                struct shader_reg reg;
+                                TRACE("Input reg declaration\n");
+                                memset(&reg, 0, sizeof(reg));
+                                reg.type = BWRITERSPR_INPUT;
+                                reg.regnum = $3;
+                                reg.rel_reg = NULL;
+                                reg.srcmod = 0;
+                                reg.writemask = BWRITERSP_WRITEMASK_ALL;
+                                ctx->funcs->dcl_input(ctx, $2.dclusage, $2.regnum, &reg);
+                            }
+                    | INSTR_DCL dclusage REG_INPUT writemask
+                            {
+                                struct shader_reg reg;
+                                TRACE("Input reg declaration\n");
+                                memset(&reg, 0, sizeof(reg));
+                                reg.type = BWRITERSPR_INPUT;
+                                reg.regnum = $3;
+                                reg.rel_reg = NULL;
+                                reg.srcmod = 0;
+                                reg.writemask = $4;
+                                ctx->funcs->dcl_input(ctx, $2.dclusage, $2.regnum, &reg);
+                            }
+                    | INSTR_DCL sampdcl REG_SAMPLER
+                            {
+                                TRACE("Sampler declared\n");
+                                ctx->funcs->dcl_sampler(ctx, $2, $3, ctx->line_no);
+                            }
+                    | INSTR_DCL sampdcl REG_INPUT
+                            {
+                                TRACE("Error rule: sampler decl of input reg\n");
+                                asmparser_message(ctx, "Line %u: Sampler declarations of input regs is not valid\n",
+                                                  ctx->line_no);
+                                set_parse_status(ctx, PARSE_WARN);
+                            }
+                    | INSTR_DCL sampdcl REG_OUTPUT
+                            {
+                                TRACE("Error rule: sampler decl of output reg\n");
+                                asmparser_message(ctx, "Line %u: Sampler declarations of output regs is not valid\n",
+                                                  ctx->line_no);
+                                set_parse_status(ctx, PARSE_WARN);
+                            }
+                    | INSTR_DEF REG_CONSTFLOAT ',' IMMVAL ',' IMMVAL ',' IMMVAL ',' IMMVAL
+                            {
+                                ctx->funcs->constF(ctx, $2, $4.val, $6.val, $8.val, $10.val);
+                            }
+                    | INSTR_DEFI REG_CONSTINT ',' IMMVAL ',' IMMVAL ',' IMMVAL ',' IMMVAL
+                            {
+                                ctx->funcs->constI(ctx, $2, $4.val, $6.val, $8.val, $10.val);
+                            }
+                    | INSTR_DEFB REG_CONSTBOOL ',' MYBOOL
+                            {
+                                ctx->funcs->constB(ctx, $2, $4);
+                            }
+                    | INSTR_REP sregs
+                            {
+                                TRACE("REP\n");
+                                ctx->funcs->instr(ctx, BWRITERSIO_REP, 0, 0, 0, 0, &$2, 1);
+                            }
+                    | INSTR_ENDREP
+                            {
+                                TRACE("ENDREP\n");
+                                ctx->funcs->instr(ctx, BWRITERSIO_ENDREP, 0, 0, 0, 0, 0, 0);
+                            }
+                    | INSTR_IF sregs
+                            {
+                                TRACE("IF\n");
+                                ctx->funcs->instr(ctx, BWRITERSIO_IF, 0, 0, 0, 0, &$2, 1);
+                            }
+                    | INSTR_IF comp sregs
+                            {
+                                TRACE("IFC\n");
+                                ctx->funcs->instr(ctx, BWRITERSIO_IFC, 0, 0, $2, 0, &$3, 2);
+                            }
+                    | INSTR_ELSE
+                            {
+                                TRACE("ELSE\n");
+                                ctx->funcs->instr(ctx, BWRITERSIO_ELSE, 0, 0, 0, 0, 0, 0);
+                            }
+                    | INSTR_ENDIF
+                            {
+                                TRACE("ENDIF\n");
+                                ctx->funcs->instr(ctx, BWRITERSIO_ENDIF, 0, 0, 0, 0, 0, 0);
+                            }
+                    | INSTR_BREAK
+                            {
+                                TRACE("BREAK\n");
+                                ctx->funcs->instr(ctx, BWRITERSIO_BREAK, 0, 0, 0, 0, 0, 0);
+                            }
+                    | INSTR_BREAK comp sregs
+                            {
+                                TRACE("BREAKC\n");
+                                ctx->funcs->instr(ctx, BWRITERSIO_BREAKC, 0, 0, $2, 0, &$3, 2);
+                            }
+                    | INSTR_BREAKP sregs
+                            {
+                                TRACE("BREAKP\n");
+                                ctx->funcs->instr(ctx, BWRITERSIO_BREAKP, 0, 0, 0, 0, &$2, 1);
+                            }
+                    | INSTR_CALL sregs
+                            {
+                                TRACE("CALL\n");
+                                ctx->funcs->instr(ctx, BWRITERSIO_CALL, 0, 0, 0, 0, &$2, 1);
+                            }
+                    | INSTR_CALLNZ sregs
+                            {
+                                TRACE("CALLNZ\n");
+                                ctx->funcs->instr(ctx, BWRITERSIO_CALLNZ, 0, 0, 0, 0, &$2, 2);
+                            }
+                    | INSTR_LOOP sregs
+                            {
+                                TRACE("LOOP\n");
+                                ctx->funcs->instr(ctx, BWRITERSIO_LOOP, 0, 0, 0, 0, &$2, 2);
+                            }
+                    | INSTR_RET
+                            {
+                                TRACE("RET\n");
+                                ctx->funcs->instr(ctx, BWRITERSIO_RET, 0, 0, 0, 0, 0, 0);
+                            }
+                    | INSTR_ENDLOOP
+                            {
+                                TRACE("ENDLOOP\n");
+                                ctx->funcs->instr(ctx, BWRITERSIO_ENDLOOP, 0, 0, 0, 0, 0, 0);
+                            }
+                    | INSTR_LABEL sregs
+                            {
+                                TRACE("LABEL\n");
+                                ctx->funcs->instr(ctx, BWRITERSIO_LABEL, 0, 0, 0, 0, &$2, 1);
+                            }
+                    | INSTR_SETP comp dreg ',' sregs
+                            {
+                                TRACE("SETP\n");
+                                ctx->funcs->instr(ctx, BWRITERSIO_SETP, 0, 0, $2, &$3, &$5, 2);
+                            }
+                    | INSTR_TEXLDL omods dreg ',' sregs
+                            {
+                                TRACE("TEXLDL\n");
+                                ctx->funcs->instr(ctx, BWRITERSIO_TEXLDL, $2.mod, $2.shift, 0, &$3, &$5, 2);
+                            }
+                    | INSTR_LIT omods dreg ',' sregs
+                            {
+                                TRACE("LIT\n");
+                                ctx->funcs->instr(ctx, BWRITERSIO_LIT, $2.mod, $2.shift, 0, &$3, &$5, 1);
+                            }
+                    | INSTR_MOVA dreg ',' sregs
+                            {
+                                TRACE("MOVA\n");
+                                ctx->funcs->instr(ctx, BWRITERSIO_MOVA, 0, 0, 0, &$2, &$4, 1);
+                            }
+                    | INSTR_CND omods dreg ',' sregs
+                            {
+                                TRACE("CND\n");
+                                ctx->funcs->instr(ctx, BWRITERSIO_CND, $2.mod, $2.shift, 0, &$3, &$5, 3);
+                            }
+                    | INSTR_CMP omods dreg ',' sregs
+                            {
+                                TRACE("CMP\n");
+                                ctx->funcs->instr(ctx, BWRITERSIO_CMP, $2.mod, $2.shift, 0, &$3, &$5, 3);
+                            }
+                    | INSTR_DP2ADD omods dreg ',' sregs
+                            {
+                                TRACE("DP2ADD\n");
+                                ctx->funcs->instr(ctx, BWRITERSIO_DP2ADD, $2.mod, $2.shift, 0, &$3, &$5, 3);
+                            }
+                    | INSTR_TEXCOORD dreg
+                            {
+                                TRACE("TEXCOORD\n");
+                                ctx->funcs->instr(ctx, BWRITERSIO_TEXCOORD, 0, 0, 0, &$2, 0, 0);
+                            }
+                    | INSTR_TEXCRD omods dreg ',' sregs
+                            {
+                                TRACE("TEXCRD\n");
+                                /* texcoord and texcrd share the same opcode */
+                                ctx->funcs->instr(ctx, BWRITERSIO_TEXCOORD, $2.mod, $2.shift, 0, &$3, &$5, 1);
+                            }
+                    | INSTR_TEXKILL dreg
+                            {
+                                TRACE("TEXKILL\n");
+                                ctx->funcs->instr(ctx, BWRITERSIO_TEXKILL, 0, 0, 0, &$2, 0, 0);
+                            }
+                    | INSTR_TEX dreg
+                            {
+                                TRACE("TEX\n");
+                                ctx->funcs->instr(ctx, BWRITERSIO_TEX, 0, 0, 0, &$2, 0, 0);
+                            }
+                    | INSTR_TEXDEPTH dreg
+                            {
+                                TRACE("TEXDEPTH\n");
+                                ctx->funcs->instr(ctx, BWRITERSIO_TEXDEPTH, 0, 0, 0, &$2, 0, 0);
+                            }
+                    | INSTR_TEXLD omods dreg ',' sregs
+                            {
+                                TRACE("TEXLD\n");
+                                /* There is more than one acceptable syntax for texld:
+                                   with 1 sreg (PS 1.4) or
+                                   with 2 sregs (PS 2.0+)
+                                   Moreover, texld shares the same opcode as the tex instruction,
+                                   so there are a total of 3 valid syntaxes
+                                   These variations are handled in asmparser.c */
+                                ctx->funcs->instr(ctx, BWRITERSIO_TEX, $2.mod, $2.shift, 0, &$3, &$5, 2);
+                            }
+                    | INSTR_TEXLDP omods dreg ',' sregs
+                            {
+                                TRACE("TEXLDP\n");
+                                ctx->funcs->instr(ctx, BWRITERSIO_TEX | ( BWRITERSI_TEXLD_PROJECT << BWRITER_OPCODESPECIFICCONTROL_SHIFT ), $2.mod, $2.shift, 0, &$3, &$5, 2);
+                            }
+                    | INSTR_TEXLDB omods dreg ',' sregs
+                            {
+                                TRACE("TEXLDB\n");
+                                ctx->funcs->instr(ctx, BWRITERSIO_TEX | ( BWRITERSI_TEXLD_BIAS << BWRITER_OPCODESPECIFICCONTROL_SHIFT ), $2.mod, $2.shift, 0, &$3, &$5, 2);
+                            }
+                    | INSTR_TEXBEM dreg ',' sregs
+                            {
+                                TRACE("TEXBEM\n");
+                                ctx->funcs->instr(ctx, BWRITERSIO_TEXBEM, 0, 0, 0, &$2, &$4, 1);
+                            }
+                    | INSTR_TEXBEML dreg ',' sregs
+                            {
+                                TRACE("TEXBEML\n");
+                                ctx->funcs->instr(ctx, BWRITERSIO_TEXBEML, 0, 0, 0, &$2, &$4, 1);
+                            }
+                    | INSTR_TEXREG2AR dreg ',' sregs
+                            {
+                                TRACE("TEXREG2AR\n");
+                                ctx->funcs->instr(ctx, BWRITERSIO_TEXREG2AR, 0, 0, 0, &$2, &$4, 1);
+                            }
+                    | INSTR_TEXREG2GB dreg ',' sregs
+                            {
+                                TRACE("TEXREG2GB\n");
+                                ctx->funcs->instr(ctx, BWRITERSIO_TEXREG2GB, 0, 0, 0, &$2, &$4, 1);
+                            }
+                    | INSTR_TEXREG2RGB dreg ',' sregs
+                            {
+                                TRACE("TEXREG2RGB\n");
+                                ctx->funcs->instr(ctx, BWRITERSIO_TEXREG2RGB, 0, 0, 0, &$2, &$4, 1);
+                            }
+                    | INSTR_TEXM3x2PAD dreg ',' sregs
+                            {
+                                TRACE("TEXM3x2PAD\n");
+                                ctx->funcs->instr(ctx, BWRITERSIO_TEXM3x2PAD, 0, 0, 0, &$2, &$4, 1);
+                            }
+                    | INSTR_TEXM3x3PAD dreg ',' sregs
+                            {
+                                TRACE("INSTR_TEXM3x3PAD\n");
+                                ctx->funcs->instr(ctx, BWRITERSIO_TEXM3x3PAD, 0, 0, 0, &$2, &$4, 1);
+                            }
+                    | INSTR_TEXM3x3DIFF dreg ',' sregs /* ??? That one's in wined3d but not the sdk */
+                            {
+                                ERR("INSTR_TEXM3x3DIFF\n");
+                            }
+                    | INSTR_TEXM3x3SPEC dreg ',' sregs
+                            {
+                                TRACE("TEXM3x3SPEC\n");
+                                ctx->funcs->instr(ctx, BWRITERSIO_TEXM3x3SPEC, 0, 0, 0, &$2, &$4, 2);
+                            }
+                    | INSTR_TEXM3x3VSPEC dreg ',' sregs
+                            {
+                                TRACE("TEXM3x3VSPEC\n");
+                                ctx->funcs->instr(ctx, BWRITERSIO_TEXM3x3VSPEC, 0, 0, 0, &$2, &$4, 1);
+                            }
+                    | INSTR_TEXM3x3TEX dreg ',' sregs
+                            {
+                                TRACE("TEXM3x3TEX\n");
+                                ctx->funcs->instr(ctx, BWRITERSIO_TEXM3x3TEX, 0, 0, 0, &$2, &$4, 1);
+                            }
+                    | INSTR_TEXDP3TEX dreg ',' sregs
+                            {
+                                TRACE("TEXDP3TEX\n");
+                                ctx->funcs->instr(ctx, BWRITERSIO_TEXDP3TEX, 0, 0, 0, &$2, &$4, 1);
+                            }
+                    | INSTR_TEXM3x2DEPTH dreg ',' sregs
+                            {
+                                TRACE("TEXM3x2DEPTH\n");
+                                ctx->funcs->instr(ctx, BWRITERSIO_TEXM3x2DEPTH, 0, 0, 0, &$2, &$4, 1);
+                            }
+                    | INSTR_TEXM3x2TEX dreg ',' sregs
+                            {
+                                TRACE("TEXM3x2TEX\n");
+                                ctx->funcs->instr(ctx, BWRITERSIO_TEXM3x2TEX, 0, 0, 0, &$2, &$4, 1);
+                            }
+                    | INSTR_TEXDP3 dreg ',' sregs
+                            {
+                                TRACE("TEXDP3\n");
+                                ctx->funcs->instr(ctx, BWRITERSIO_TEXDP3, 0, 0, 0, &$2, &$4, 1);
+                            }
+                    | INSTR_TEXM3x3 dreg ',' sregs
+                            {
+                                TRACE("TEXM3x3\n");
+                                ctx->funcs->instr(ctx, BWRITERSIO_TEXM3x3, 0, 0, 0, &$2, &$4, 1);
+                            }
+                    | INSTR_BEM dreg ',' sregs
+                            {
+                                TRACE("BEM\n");
+                                ctx->funcs->instr(ctx, BWRITERSIO_BEM, 0, 0, 0, &$2, &$4, 2);
+                            }
+                    | INSTR_DSX dreg ',' sregs
+                            {
+                                TRACE("DSX\n");
+                                ctx->funcs->instr(ctx, BWRITERSIO_DSX, 0, 0, 0, &$2, &$4, 1);
+                            }
+                    | INSTR_DSY dreg ',' sregs
+                            {
+                                TRACE("DSY\n");
+                                ctx->funcs->instr(ctx, BWRITERSIO_DSY, 0, 0, 0, &$2, &$4, 1);
+                            }
+                    | INSTR_TEXLDD dreg ',' sregs
+                            {
+                                TRACE("TEXLDD\n");
+                                ctx->funcs->instr(ctx, BWRITERSIO_TEXLDD, 0, 0, 0, &$2, &$4, 4);
+                            }
+                    | INSTR_PHASE
+                            {
+                                TRACE("PHASE\n");
+                                ctx->funcs->instr(ctx, BWRITERSIO_PHASE, 0, 0, 0, 0, 0, 0);
+                            }
+
+
+dreg:                 dreg_name rel_reg
+                            {
+                                $$.regnum = $1.regnum;
+                                $$.type = $1.type;
+                                $$.writemask = BWRITERSP_WRITEMASK_ALL;
+                                $$.srcmod = BWRITERSPSM_NONE;
+                                set_rel_reg(&$$, &$2);
+                            }
+                    | dreg_name writemask
+                            {
+                                $$.regnum = $1.regnum;
+                                $$.type = $1.type;
+                                $$.writemask = $2;
+                                $$.srcmod = BWRITERSPSM_NONE;
+                                $$.rel_reg = NULL;
+                            }
+
+dreg_name:            REG_TEMP
+                        {
+                            $$.regnum = $1; $$.type = BWRITERSPR_TEMP;
+                        }
+                    | REG_OUTPUT
+                        {
+                            $$.regnum = $1; $$.type = BWRITERSPR_OUTPUT;
+                        }
+                    | REG_INPUT
+                        {
+                            asmparser_message(ctx, "Line %u: Register v%u is not a valid destination register\n",
+                                              ctx->line_no, $1);
+                            set_parse_status(ctx, PARSE_WARN);
+                        }
+                    | REG_CONSTFLOAT
+                        {
+                            asmparser_message(ctx, "Line %u: Register c%u is not a valid destination register\n",
+                                              ctx->line_no, $1);
+                            set_parse_status(ctx, PARSE_WARN);
+                        }
+                    | REG_CONSTINT
+                        {
+                            asmparser_message(ctx, "Line %u: Register i%u is not a valid destination register\n",
+                                              ctx->line_no, $1);
+                            set_parse_status(ctx, PARSE_WARN);
+                        }
+                    | REG_CONSTBOOL
+                        {
+                            asmparser_message(ctx, "Line %u: Register b%u is not a valid destination register\n",
+                                              ctx->line_no, $1);
+                            set_parse_status(ctx, PARSE_WARN);
+                        }
+                    | REG_TEXTURE
+                        {
+                            $$.regnum = $1; $$.type = BWRITERSPR_TEXTURE;
+                        }
+                    | REG_TEXCRDOUT
+                        {
+                            $$.regnum = $1; $$.type = BWRITERSPR_TEXCRDOUT;
+                        }
+                    | REG_SAMPLER
+                        {
+                            asmparser_message(ctx, "Line %u: Register s%u is not a valid destination register\n",
+                                              ctx->line_no, $1);
+                            set_parse_status(ctx, PARSE_WARN);
+                        }
+                    | REG_OPOS
+                        {
+                            $$.regnum = BWRITERSRO_POSITION ; $$.type = BWRITERSPR_RASTOUT;
+                        }
+                    | REG_OPTS
+                        {
+                            $$.regnum = BWRITERSRO_POINT_SIZE ; $$.type = BWRITERSPR_RASTOUT;
+                        }
+                    | REG_OFOG
+                        {
+                            $$.regnum = BWRITERSRO_FOG ; $$.type = BWRITERSPR_RASTOUT;
+                        }
+                    | REG_VERTEXCOLOR
+                        {
+                            $$.regnum = $1; $$.type = BWRITERSPR_ATTROUT;
+                        }
+                    | REG_FRAGCOLOR
+                        {
+                            $$.regnum = $1; $$.type = BWRITERSPR_COLOROUT;
+                        }
+                    | REG_FRAGDEPTH
+                        {
+                            $$.regnum = 0; $$.type = BWRITERSPR_DEPTHOUT;
+                        }
+                    | REG_PREDICATE
+                        {
+                            $$.regnum = 0; $$.type = BWRITERSPR_PREDICATE;
+                        }
+                    | REG_VPOS
+                        {
+                            asmparser_message(ctx, "Line %u: Register vPos is not a valid destination register\n",
+                                              ctx->line_no);
+                            set_parse_status(ctx, PARSE_WARN);
+                        }
+                    | REG_VFACE
+                        {
+                            asmparser_message(ctx, "Line %u: Register vFace is not a valid destination register\n",
+                                              ctx->line_no);
+                            set_parse_status(ctx, PARSE_WARN);
+                        }
+                    | REG_ADDRESS
+                        {
+                            /* index 0 is hardcoded for the addr register */
+                            $$.regnum = 0; $$.type = BWRITERSPR_ADDR;
+                        }
+                    | REG_LOOP
+                        {
+                            asmparser_message(ctx, "Line %u: Register aL is not a valid destination register\n",
+                                              ctx->line_no);
+                            set_parse_status(ctx, PARSE_WARN);
+                        }
+
+writemask:            SWIZZLE
+                        {
+                            TRACE("Got a writemask\n");
+                            if($1.writemask == 0) {
+                                asmparser_message(ctx, "Line %u: Invalid writemask specified\n",
+                                                  ctx->line_no);
+                                set_parse_status(ctx, PARSE_ERR);
+                                /* Provide a correct writemask to prevent follow-up complaints */
+                                $$ = BWRITERSP_WRITEMASK_ALL;
+                            } else {
+                                $$ = $1.writemask;
+                            }
+                        }
+
+swizzle:              /* empty */
+                        {
+                            $$ = BWRITERVS_NOSWIZZLE;
+                            TRACE("Default swizzle: %08x\n", $$);
+                        }
+                    | SWIZZLE
+                        {
+                            if($1.swizzle == SWIZZLE_ERR) {
+                                asmparser_message(ctx, "Line %u: Invalid swizzle\n",
+                                                  ctx->line_no);
+                                set_parse_status(ctx, PARSE_ERR);
+                                /* Provide a correct swizzle to prevent follow-up complaints */
+                                $$ = BWRITERSP_NOSWIZZLE;
+                            }
+                            else {
+                                TRACE("Got a swizzle: %08x\n", $1.swizzle);
+                                $$ = $1.swizzle;
+                            }
+                        }
+
+omods:                 /* Empty */
+                        {
+                            $$.mod = 0;
+                            $$.shift = 0;
+                        }
+                    | omods omodifier
+                        {
+                            $$.mod = $1.mod | $2.mod;
+                            if($1.shift && $2.shift) {
+                                asmparser_message(ctx, "Line %u: More than one shift flag\n",
+                                                  ctx->line_no);
+                                set_parse_status(ctx, PARSE_ERR);
+                                $$.shift = $1.shift;
+                            } else {
+                                $$.shift = $1.shift | $2.shift;
+                            }
+                        }
+
+omodifier:            SHIFT_X2
+                        {
+                            $$.mod = 0;
+                            $$.shift = 1;
+                        }
+                    | SHIFT_X4
+                        {
+                            $$.mod = 0;
+                            $$.shift = 2;
+                        }
+                    | SHIFT_X8
+                        {
+                            $$.mod = 0;
+                            $$.shift = 3;
+                        }
+                    | SHIFT_D2
+                        {
+                            $$.mod = 0;
+                            $$.shift = 15;
+                        }
+                    | SHIFT_D4
+                        {
+                            $$.mod = 0;
+                            $$.shift = 14;
+                        }
+                    | SHIFT_D8
+                        {
+                            $$.mod = 0;
+                            $$.shift = 13;
+                        }
+                    | MOD_SAT
+                        {
+                            $$.mod = BWRITERSPDM_SATURATE;
+                            $$.shift = 0;
+                        }
+                    | MOD_PP
+                        {
+                            $$.mod = BWRITERSPDM_PARTIALPRECISION;
+                            $$.shift = 0;
+                        }
+                    | MOD_CENTROID
+                        {
+                            $$.mod = BWRITERSPDM_MSAMPCENTROID;
+                            $$.shift = 0;
+                        }
+
+sregs:                sreg
+                        {
+                            $$.reg[0] = $1;
+                            $$.count = 1;
+                        }
+                    | sregs ',' sreg
+                        {
+                            if($$.count == MAX_SRC_REGS){
+                                asmparser_message(ctx, "Line %u: Too many source registers in this instruction\n",
+                                                  ctx->line_no);
+                                set_parse_status(ctx, PARSE_ERR);
+                            }
+                            else
+                                $$.reg[$$.count++] = $3;
+                        }
+
+sreg:                   sreg_name rel_reg swizzle
+                        {
+                            $$.type = $1.type;
+                            $$.regnum = $1.regnum;
+                            $$.swizzle = $3;
+                            $$.srcmod = BWRITERSPSM_NONE;
+                            set_rel_reg(&$$, &$2);
+                        }
+                    | sreg_name rel_reg smod swizzle
+                        {
+                            $$.type = $1.type;
+                            $$.regnum = $1.regnum;
+                            set_rel_reg(&$$, &$2);
+                            $$.srcmod = $3;
+                            $$.swizzle = $4;
+                        }
+                    | '-' sreg_name rel_reg swizzle
+                        {
+                            $$.type = $2.type;
+                            $$.regnum = $2.regnum;
+                            $$.srcmod = BWRITERSPSM_NEG;
+                            set_rel_reg(&$$, &$3);
+                            $$.swizzle = $4;
+                        }
+                    | '-' sreg_name rel_reg smod swizzle
+                        {
+                            $$.type = $2.type;
+                            $$.regnum = $2.regnum;
+                            set_rel_reg(&$$, &$3);
+                            switch($4) {
+                                case BWRITERSPSM_BIAS: $$.srcmod = BWRITERSPSM_BIASNEG; break;
+                                case BWRITERSPSM_X2:   $$.srcmod = BWRITERSPSM_X2NEG;   break;
+                                case BWRITERSPSM_SIGN: $$.srcmod = BWRITERSPSM_SIGNNEG; break;
+                                case BWRITERSPSM_ABS:  $$.srcmod = BWRITERSPSM_ABSNEG;  break;
+                                case BWRITERSPSM_DZ:
+                                    asmparser_message(ctx, "Line %u: Incompatible source modifiers: NEG and DZ\n",
+                                                      ctx->line_no);
+                                    set_parse_status(ctx, PARSE_ERR);
+                                    break;
+                                case BWRITERSPSM_DW:
+                                    asmparser_message(ctx, "Line %u: Incompatible source modifiers: NEG and DW\n",
+                                                      ctx->line_no);
+                                    set_parse_status(ctx, PARSE_ERR);
+                                    break;
+                                default:
+                                    FIXME("Unhandled combination of NEGATE and %u\n", $4);
+                            }
+                            $$.swizzle = $5;
+                        }
+                    | IMMVAL '-' sreg_name rel_reg swizzle
+                        {
+                            if($1.val != 1.0 || (!$1.integer)) {
+                                asmparser_message(ctx, "Line %u: Only \"1 - reg\" is valid for D3DSPSM_COMP, "
+                                                  "%g - reg found\n", ctx->line_no, $1.val);
+                                set_parse_status(ctx, PARSE_ERR);
+                            }
+                            /* Complement - not compatible with other source modifiers */
+                            $$.type = $3.type;
+                            $$.regnum = $3.regnum;
+                            $$.srcmod = BWRITERSPSM_COMP;
+                            set_rel_reg(&$$, &$4);
+                            $$.swizzle = $5;
+                        }
+                    | IMMVAL '-' sreg_name rel_reg smod swizzle
+                        {
+                            /* For nicer error reporting */
+                            if($1.val != 1.0 || (!$1.integer)) {
+                                asmparser_message(ctx, "Line %u: Only \"1 - reg\" is valid for D3DSPSM_COMP\n",
+                                                  ctx->line_no);
+                                set_parse_status(ctx, PARSE_ERR);
+                            } else {
+                                asmparser_message(ctx, "Line %u: Incompatible source modifiers: D3DSPSM_COMP and %s\n",
+                                                  ctx->line_no,
+                                                  debug_print_srcmod($5));
+                                set_parse_status(ctx, PARSE_ERR);
+                            }
+                        }
+                    | SMOD_NOT sreg_name swizzle
+                        {
+                            $$.type = $2.type;
+                            $$.regnum = $2.regnum;
+                            $$.rel_reg = NULL;
+                            $$.srcmod = BWRITERSPSM_NOT;
+                            $$.swizzle = $3;
+                        }
+
+rel_reg:               /* empty */
+                        {
+                            $$.has_rel_reg = FALSE;
+                            $$.additional_offset = 0;
+                        }
+                    | '[' immsum ']'
+                        {
+                            $$.has_rel_reg = FALSE;
+                            $$.additional_offset = $2.val;
+                        }
+                    | '[' relreg_name swizzle ']'
+                        {
+                            $$.has_rel_reg = TRUE;
+                            $$.type = $2.type;
+                            $$.additional_offset = 0;
+                            $$.rel_regnum = $2.regnum;
+                            $$.swizzle = $3;
+                        }
+                    | '[' immsum '+' relreg_name swizzle ']'
+                        {
+                            $$.has_rel_reg = TRUE;
+                            $$.type = $4.type;
+                            $$.additional_offset = $2.val;
+                            $$.rel_regnum = $4.regnum;
+                            $$.swizzle = $5;
+                        }
+                    | '[' relreg_name swizzle '+' immsum ']'
+                        {
+                            $$.has_rel_reg = TRUE;
+                            $$.type = $2.type;
+                            $$.additional_offset = $5.val;
+                            $$.rel_regnum = $2.regnum;
+                            $$.swizzle = $3;
+                        }
+                    | '[' immsum '+' relreg_name swizzle '+' immsum ']'
+                        {
+                            $$.has_rel_reg = TRUE;
+                            $$.type = $4.type;
+                            $$.additional_offset = $2.val + $7.val;
+                            $$.rel_regnum = $4.regnum;
+                            $$.swizzle = $5;
+                        }
+
+immsum:               IMMVAL
+                        {
+                            if(!$1.integer) {
+                                asmparser_message(ctx, "Line %u: Unexpected float %f\n",
+                                                  ctx->line_no, $1.val);
+                                set_parse_status(ctx, PARSE_ERR);
+                            }
+                            $$.val = $1.val;
+                        }
+                    | immsum '+' IMMVAL
+                        {
+                            if(!$3.integer) {
+                                asmparser_message(ctx, "Line %u: Unexpected float %f\n",
+                                                  ctx->line_no, $3.val);
+                                set_parse_status(ctx, PARSE_ERR);
+                            }
+                            $$.val = $1.val + $3.val;
+                        }
+
+smod:                SMOD_BIAS
+                        {
+                            $$ = BWRITERSPSM_BIAS;
+                        }
+                    | SHIFT_X2
+                        {
+                            $$ = BWRITERSPSM_X2;
+                        }
+                    | SMOD_SCALEBIAS
+                        {
+                            $$ = BWRITERSPSM_SIGN;
+                        }
+                    | SMOD_DZ
+                        {
+                            $$ = BWRITERSPSM_DZ;
+                        }
+                    | SMOD_DW
+                        {
+                            $$ = BWRITERSPSM_DW;
+                        }
+                    | SMOD_ABS
+                        {
+                            $$ = BWRITERSPSM_ABS;
+                        }
+
+relreg_name:        REG_ADDRESS
+                        {
+                            $$.regnum = 0; $$.type = BWRITERSPR_ADDR;
+                        }
+                    | REG_LOOP
+                        {
+                            $$.regnum = 0; $$.type = BWRITERSPR_LOOP;
+                        }
+
+sreg_name:            REG_TEMP
+                        {
+                            $$.regnum = $1; $$.type = BWRITERSPR_TEMP;
+                        }
+                    | REG_OUTPUT
+                        {
+                            asmparser_message(ctx, "Line %u: Register o%u is not a valid source register\n",
+                                              ctx->line_no, $1);
+                            set_parse_status(ctx, PARSE_WARN);
+                        }
+                    | REG_INPUT
+                        {
+                            $$.regnum = $1; $$.type = BWRITERSPR_INPUT;
+                        }
+                    | REG_CONSTFLOAT
+                        {
+                            $$.regnum = $1; $$.type = BWRITERSPR_CONST;
+                        }
+                    | REG_CONSTINT
+                        {
+                            $$.regnum = $1; $$.type = BWRITERSPR_CONSTINT;
+                        }
+                    | REG_CONSTBOOL
+                        {
+                            $$.regnum = $1; $$.type = BWRITERSPR_CONSTBOOL;
+                        }
+                    | REG_TEXTURE
+                        {
+                            $$.regnum = $1; $$.type = BWRITERSPR_TEXTURE;
+                        }
+                    | REG_TEXCRDOUT
+                        {
+                            asmparser_message(ctx, "Line %u: Register oT%u is not a valid source register\n",
+                                              ctx->line_no, $1);
+                            set_parse_status(ctx, PARSE_WARN);
+                        }
+                    | REG_SAMPLER
+                        {
+                            $$.regnum = $1; $$.type = BWRITERSPR_SAMPLER;
+                        }
+                    | REG_OPOS
+                        {
+                            asmparser_message(ctx, "Line %u: Register oPos is not a valid source register\n",
+                                              ctx->line_no);
+                            set_parse_status(ctx, PARSE_WARN);
+                        }
+                    | REG_OFOG
+                        {
+                            asmparser_message(ctx, "Line %u: Register oFog is not a valid source register\n",
+                                              ctx->line_no);
+                            set_parse_status(ctx, PARSE_WARN);
+                        }
+                    | REG_VERTEXCOLOR
+                        {
+                            asmparser_message(ctx, "Line %u: Register oD%u is not a valid source register\n",
+                                              ctx->line_no, $1);
+                            set_parse_status(ctx, PARSE_WARN);
+                        }
+                    | REG_FRAGCOLOR
+                        {
+                            asmparser_message(ctx, "Line %u: Register oC%u is not a valid source register\n",
+                                              ctx->line_no, $1);
+                            set_parse_status(ctx, PARSE_WARN);
+                        }
+                    | REG_FRAGDEPTH
+                        {
+                            asmparser_message(ctx, "Line %u: Register oDepth is not a valid source register\n",
+                                              ctx->line_no);
+                            set_parse_status(ctx, PARSE_WARN);
+                        }
+                    | REG_PREDICATE
+                        {
+                            $$.regnum = 0; $$.type = BWRITERSPR_PREDICATE;
+                        }
+                    | REG_VPOS
+                        {
+                            /* No constants defined for this ? */
+                            $$.regnum = 0; $$.type = BWRITERSPR_MISCTYPE;
+                        }
+                    | REG_VFACE
+                        {
+                            /* No constants defined for this ? */
+                            $$.regnum = 1; $$.type = BWRITERSPR_MISCTYPE;
+                        }
+                    | REG_ADDRESS
+                        {
+                            $$.regnum = 0; $$.type = BWRITERSPR_ADDR;
+                        }
+                    | REG_LOOP
+                        {
+                            $$.regnum = 0; $$.type = BWRITERSPR_LOOP;
+                        }
+                    | REG_LABEL
+                        {
+                            $$.regnum = $1; $$.type = BWRITERSPR_LABEL;
+                        }
+                    | IMMVAL            { FIXME("Immediate src argument\n");  }
+
+comp:                 COMP_GT           { $$ = BWRITER_COMPARISON_GT;       }
+                    | COMP_LT           { $$ = BWRITER_COMPARISON_LT;       }
+                    | COMP_GE           { $$ = BWRITER_COMPARISON_GE;       }
+                    | COMP_LE           { $$ = BWRITER_COMPARISON_LE;       }
+                    | COMP_EQ           { $$ = BWRITER_COMPARISON_EQ;       }
+                    | COMP_NE           { $$ = BWRITER_COMPARISON_NE;       }
+
+dclusage:             USAGE_POSITION
+                        {
+                            TRACE("dcl_position%u\n", $1);
+                            $$.regnum = $1;
+                            $$.dclusage = BWRITERDECLUSAGE_POSITION;
+                        }
+                    | USAGE_BLENDWEIGHT
+                        {
+                            TRACE("dcl_blendweight%u\n", $1);
+                            $$.regnum = $1;
+                            $$.dclusage = BWRITERDECLUSAGE_BLENDWEIGHT;
+                        }
+                    | USAGE_BLENDINDICES
+                        {
+                            TRACE("dcl_blendindices%u\n", $1);
+                            $$.regnum = $1;
+                            $$.dclusage = BWRITERDECLUSAGE_BLENDINDICES;
+                        }
+                    | USAGE_NORMAL
+                        {
+                            TRACE("dcl_normal%u\n", $1);
+                            $$.regnum = $1;
+                            $$.dclusage = BWRITERDECLUSAGE_NORMAL;
+                        }
+                    | USAGE_PSIZE
+                        {
+                            TRACE("dcl_psize%u\n", $1);
+                            $$.regnum = $1;
+                            $$.dclusage = BWRITERDECLUSAGE_PSIZE;
+                        }
+                    | USAGE_TEXCOORD
+                        {
+                            TRACE("dcl_texcoord%u\n", $1);
+                            $$.regnum = $1;
+                            $$.dclusage = BWRITERDECLUSAGE_TEXCOORD;
+                        }
+                    | USAGE_TANGENT
+                        {
+                            TRACE("dcl_tangent%u\n", $1);
+                            $$.regnum = $1;
+                            $$.dclusage = BWRITERDECLUSAGE_TANGENT;
+                        }
+                    | USAGE_BINORMAL
+                        {
+                            TRACE("dcl_binormal%u\n", $1);
+                            $$.regnum = $1;
+                            $$.dclusage = BWRITERDECLUSAGE_BINORMAL;
+                        }
+                    | USAGE_TESSFACTOR
+                        {
+                            TRACE("dcl_tessfactor%u\n", $1);
+                            $$.regnum = $1;
+                            $$.dclusage = BWRITERDECLUSAGE_TESSFACTOR;
+                        }
+                    | USAGE_POSITIONT
+                        {
+                            TRACE("dcl_positiont%u\n", $1);
+                            $$.regnum = $1;
+                            $$.dclusage = BWRITERDECLUSAGE_POSITIONT;
+                        }
+                    | USAGE_COLOR
+                        {
+                            TRACE("dcl_color%u\n", $1);
+                            $$.regnum = $1;
+                            $$.dclusage = BWRITERDECLUSAGE_COLOR;
+                        }
+                    | USAGE_FOG
+                        {
+                            TRACE("dcl_fog%u\n", $1);
+                            $$.regnum = $1;
+                            $$.dclusage = BWRITERDECLUSAGE_FOG;
+                        }
+                    | USAGE_DEPTH
+                        {
+                            TRACE("dcl_depth%u\n", $1);
+                            $$.regnum = $1;
+                            $$.dclusage = BWRITERDECLUSAGE_DEPTH;
+                        }
+                    | USAGE_SAMPLE
+                        {
+                            TRACE("dcl_sample%u\n", $1);
+                            $$.regnum = $1;
+                            $$.dclusage = BWRITERDECLUSAGE_SAMPLE;
+                        }
+
+sampdcl:              SAMPTYPE_1D
+                        {
+                            $$ = BWRITERSTT_1D;
+                        }
+                    | SAMPTYPE_2D
+                        {
+                            $$ = BWRITERSTT_2D;
+                        }
+                    | SAMPTYPE_CUBE
+                        {
+                            $$ = BWRITERSTT_CUBE;
+                        }
+                    | SAMPTYPE_VOLUME
+                        {
+                            $$ = BWRITERSTT_VOLUME;
+                        }
+
+predicate:            '(' REG_PREDICATE swizzle ')'
+                        {
+                            $$.type = BWRITERSPR_PREDICATE;
+                            $$.regnum = 0;
+                            $$.rel_reg = NULL;
+                            $$.srcmod = BWRITERSPSM_NONE;
+                            $$.swizzle = $3;
+                        }
+                    | '(' SMOD_NOT REG_PREDICATE swizzle ')'
+                        {
+                            $$.type = BWRITERSPR_PREDICATE;
+                            $$.regnum = 0;
+                            $$.rel_reg = NULL;
+                            $$.srcmod = BWRITERSPSM_NOT;
+                            $$.swizzle = $4;
+                        }
+
+%%
+
+void asmshader_error (struct asm_parser *ctx, void *scanner, char const *s) {
+    asmparser_message(ctx, "Line %u: Error \"%s\" from bison\n", ctx->line_no, s);
+    set_parse_status(ctx, PARSE_ERR);
+}
+
+/* Error reporting function */
+void asmparser_message(struct asm_parser *ctx, const char *fmt, ...) {
+    va_list args;
+    char* newbuffer;
+    int rc, newsize;
+
+    if(ctx->messagecapacity == 0) {
+        ctx->messages = asm_alloc(MESSAGEBUFFER_INITIAL_SIZE);
+        if(ctx->messages == NULL) {
+            ERR("Error allocating memory for parser messages\n");
+            return;
+        }
+        ctx->messagecapacity = MESSAGEBUFFER_INITIAL_SIZE;
+    }
+
+    while(1) {
+        va_start(args, fmt);
+        rc = vsnprintf(ctx->messages + ctx->messagesize,
+                       ctx->messagecapacity - ctx->messagesize, fmt, args);
+        va_end(args);
+
+        if (rc < 0 ||                                           /* C89 */
+            rc >= ctx->messagecapacity - ctx->messagesize) {    /* C99 */
+            /* Resize the buffer */
+            newsize = ctx->messagecapacity * 2;
+            newbuffer = asm_realloc(ctx->messages, newsize);
+            if(newbuffer == NULL){
+                ERR("Error reallocating memory for parser messages\n");
+                return;
+            }
+            ctx->messages = newbuffer;
+            ctx->messagecapacity = newsize;
+        } else {
+            ctx->messagesize += rc;
+            return;
+        }
+    }
+}
+
+/* new status is the worse between current status and parameter value */
+void set_parse_status(struct asm_parser *ctx, enum parse_status status) {
+    if(status == PARSE_ERR) ctx->status = PARSE_ERR;
+    else if(status == PARSE_WARN && ctx->status == PARSE_SUCCESS) ctx->status = PARSE_WARN;
+}
+
+struct bwriter_shader *parse_asm_shader(struct asm_parser *asm_ctx, char **messages) {
+    struct bwriter_shader *ret = NULL;
+
+    asm_ctx->shader = NULL;
+    asm_ctx->status = PARSE_SUCCESS;
+    asm_ctx->messagesize = asm_ctx->messagecapacity = 0;
+    asm_ctx->line_no = 1;
+
+    asmshader_parse(asm_ctx, asm_ctx->yyscanner);
+
+    if(asm_ctx->status != PARSE_ERR) ret = asm_ctx->shader;
+    else if(asm_ctx->shader) SlDeleteShader(asm_ctx->shader);
+
+    if(messages) {
+        if(asm_ctx->messagesize) {
+            /* Shrink the buffer to the used size */
+            *messages = asm_realloc(asm_ctx->messages, asm_ctx->messagesize + 1);
+            if(!*messages) {
+                ERR("Out of memory, no messages reported\n");
+                asm_free(asm_ctx->messages);
+            }
+        } else {
+            *messages = NULL;
+        }
+    }
+    else{
+        if(asm_ctx->messagecapacity) asm_free(asm_ctx->messages);
+    }
+
+    return ret;
+}
-- 
1.6.3.3


More information about the wine-patches mailing list