| /* |
| * 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 <stdio.h> |
| |
| WINE_DEFAULT_DEBUG_CHANNEL(asmshader); |
| |
| struct asm_parser asm_ctx; |
| |
| /* Needed lexer functions declarations */ |
| void asmshader_error(const char *s); |
| int asmshader_lex(void); |
| |
| 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; |
| } |
| } |
| |
| %} |
| |
| %union { |
| struct { |
| float val; |
| BOOL integer; |
| } immval; |
| BOOL immbool; |
| unsigned int regnum; |
| struct shader_reg reg; |
| DWORD srcmod; |
| DWORD writemask; |
| struct { |
| DWORD writemask; |
| DWORD idx; |
| DWORD last; |
| } wm_components; |
| DWORD swizzle; |
| struct { |
| DWORD swizzle; |
| DWORD idx; |
| } sw_components; |
| DWORD component; |
| 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_CMP |
| %token INSTR_DP2ADD |
| %token INSTR_TEXKILL |
| %token INSTR_TEXLD |
| %token INSTR_DSX |
| %token INSTR_DSY |
| %token INSTR_TEXLDP |
| %token INSTR_TEXLDB |
| %token INSTR_TEXLDD |
| |
| /* 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 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_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 <component> COMPONENT |
| %token <immval> IMMVAL |
| %token <immbool> IMMBOOL |
| |
| %type <reg> dreg_name |
| %type <reg> dreg |
| %type <reg> sreg_name |
| %type <reg> relreg_name |
| %type <reg> sreg |
| %type <srcmod> smod |
| %type <writemask> writemask |
| %type <wm_components> wm_components |
| %type <swizzle> swizzle |
| %type <sw_components> sw_components |
| %type <modshift> omods |
| %type <modshift> omodifier |
| %type <comptype> comp |
| %type <declaration> dclusage |
| %type <reg> dcl_inputreg |
| %type <samplertype> sampdcl |
| %type <rel_reg> rel_reg |
| %type <reg> predicate |
| %type <immval> immsum |
| %type <sregs> sregs |
| |
| %% |
| |
| shader: version_marker instructions |
| { |
| asm_ctx.funcs->end(&asm_ctx); |
| } |
| |
| version_marker: VER_VS10 |
| { |
| TRACE("Vertex shader 1.0\n"); |
| create_vs10_parser(&asm_ctx); |
| } |
| | VER_VS11 |
| { |
| TRACE("Vertex shader 1.1\n"); |
| create_vs11_parser(&asm_ctx); |
| } |
| | VER_VS20 |
| { |
| TRACE("Vertex shader 2.0\n"); |
| create_vs20_parser(&asm_ctx); |
| } |
| | VER_VS2X |
| { |
| TRACE("Vertex shader 2.x\n"); |
| create_vs2x_parser(&asm_ctx); |
| } |
| | VER_VS30 |
| { |
| TRACE("Vertex shader 3.0\n"); |
| create_vs30_parser(&asm_ctx); |
| } |
| | VER_PS10 |
| { |
| TRACE("Pixel shader 1.0\n"); |
| set_parse_status(&asm_ctx, PARSE_ERR); |
| YYABORT; |
| } |
| | VER_PS11 |
| { |
| TRACE("Pixel shader 1.1\n"); |
| set_parse_status(&asm_ctx, PARSE_ERR); |
| YYABORT; |
| } |
| | VER_PS12 |
| { |
| TRACE("Pixel shader 1.2\n"); |
| set_parse_status(&asm_ctx, PARSE_ERR); |
| YYABORT; |
| } |
| | VER_PS13 |
| { |
| TRACE("Pixel shader 1.3\n"); |
| set_parse_status(&asm_ctx, PARSE_ERR); |
| YYABORT; |
| } |
| | VER_PS14 |
| { |
| TRACE("Pixel shader 1.4\n"); |
| set_parse_status(&asm_ctx, PARSE_ERR); |
| YYABORT; |
| } |
| | VER_PS20 |
| { |
| TRACE("Pixel shader 2.0\n"); |
| create_ps20_parser(&asm_ctx); |
| } |
| | VER_PS2X |
| { |
| TRACE("Pixel shader 2.x\n"); |
| create_ps2x_parser(&asm_ctx); |
| } |
| | VER_PS30 |
| { |
| TRACE("Pixel shader 3.0\n"); |
| create_ps30_parser(&asm_ctx); |
| } |
| |
| instructions: /* empty */ |
| | instructions complexinstr |
| { |
| /* Nothing to do */ |
| } |
| |
| complexinstr: instruction |
| { |
| |
| } |
| | predicate instruction |
| { |
| TRACE("predicate\n"); |
| asm_ctx.funcs->predicate(&asm_ctx, &$1); |
| } |
| |
| instruction: INSTR_ADD omods dreg ',' sregs |
| { |
| TRACE("ADD\n"); |
| asm_ctx.funcs->instr(&asm_ctx, BWRITERSIO_ADD, $2.mod, $2.shift, 0, &$3, &$5, 2); |
| } |
| | INSTR_NOP |
| { |
| TRACE("NOP\n"); |
| asm_ctx.funcs->instr(&asm_ctx, BWRITERSIO_NOP, 0, 0, 0, 0, 0, 0); |
| } |
| | INSTR_MOV omods dreg ',' sregs |
| { |
| TRACE("MOV\n"); |
| asm_ctx.funcs->instr(&asm_ctx, BWRITERSIO_MOV, $2.mod, $2.shift, 0, &$3, &$5, 1); |
| } |
| | INSTR_SUB omods dreg ',' sregs |
| { |
| TRACE("SUB\n"); |
| asm_ctx.funcs->instr(&asm_ctx, BWRITERSIO_SUB, $2.mod, $2.shift, 0, &$3, &$5, 2); |
| } |
| | INSTR_MAD omods dreg ',' sregs |
| { |
| TRACE("MAD\n"); |
| asm_ctx.funcs->instr(&asm_ctx, BWRITERSIO_MAD, $2.mod, $2.shift, 0, &$3, &$5, 3); |
| } |
| | INSTR_MUL omods dreg ',' sregs |
| { |
| TRACE("MUL\n"); |
| asm_ctx.funcs->instr(&asm_ctx, BWRITERSIO_MUL, $2.mod, $2.shift, 0, &$3, &$5, 2); |
| } |
| | INSTR_RCP omods dreg ',' sregs |
| { |
| TRACE("RCP\n"); |
| asm_ctx.funcs->instr(&asm_ctx, BWRITERSIO_RCP, $2.mod, $2.shift, 0, &$3, &$5, 1); |
| } |
| | INSTR_RSQ omods dreg ',' sregs |
| { |
| TRACE("RSQ\n"); |
| asm_ctx.funcs->instr(&asm_ctx, BWRITERSIO_RSQ, $2.mod, $2.shift, 0, &$3, &$5, 1); |
| } |
| | INSTR_DP3 omods dreg ',' sregs |
| { |
| TRACE("DP3\n"); |
| asm_ctx.funcs->instr(&asm_ctx, BWRITERSIO_DP3, $2.mod, $2.shift, 0, &$3, &$5, 2); |
| } |
| | INSTR_DP4 omods dreg ',' sregs |
| { |
| TRACE("DP4\n"); |
| asm_ctx.funcs->instr(&asm_ctx, BWRITERSIO_DP4, $2.mod, $2.shift, 0, &$3, &$5, 2); |
| } |
| | INSTR_MIN omods dreg ',' sregs |
| { |
| TRACE("MIN\n"); |
| asm_ctx.funcs->instr(&asm_ctx, BWRITERSIO_MIN, $2.mod, $2.shift, 0, &$3, &$5, 2); |
| } |
| | INSTR_MAX omods dreg ',' sregs |
| { |
| TRACE("MAX\n"); |
| asm_ctx.funcs->instr(&asm_ctx, BWRITERSIO_MAX, $2.mod, $2.shift, 0, &$3, &$5, 2); |
| } |
| | INSTR_SLT omods dreg ',' sregs |
| { |
| TRACE("SLT\n"); |
| asm_ctx.funcs->instr(&asm_ctx, BWRITERSIO_SLT, $2.mod, $2.shift, 0, &$3, &$5, 2); |
| } |
| | INSTR_SGE omods dreg ',' sregs |
| { |
| TRACE("SGE\n"); |
| asm_ctx.funcs->instr(&asm_ctx, BWRITERSIO_SGE, $2.mod, $2.shift, 0, &$3, &$5, 2); |
| } |
| | INSTR_ABS omods dreg ',' sregs |
| { |
| TRACE("ABS\n"); |
| asm_ctx.funcs->instr(&asm_ctx, BWRITERSIO_ABS, $2.mod, $2.shift, 0, &$3, &$5, 1); |
| } |
| | INSTR_EXP omods dreg ',' sregs |
| { |
| TRACE("EXP\n"); |
| asm_ctx.funcs->instr(&asm_ctx, BWRITERSIO_EXP, $2.mod, $2.shift, 0, &$3, &$5, 1); |
| } |
| | INSTR_LOG omods dreg ',' sregs |
| { |
| TRACE("LOG\n"); |
| asm_ctx.funcs->instr(&asm_ctx, BWRITERSIO_LOG, $2.mod, $2.shift, 0, &$3, &$5, 1); |
| } |
| | INSTR_LOGP omods dreg ',' sregs |
| { |
| TRACE("LOGP\n"); |
| asm_ctx.funcs->instr(&asm_ctx, BWRITERSIO_LOGP, $2.mod, $2.shift, 0, &$3, &$5, 1); |
| } |
| | INSTR_EXPP omods dreg ',' sregs |
| { |
| TRACE("EXPP\n"); |
| asm_ctx.funcs->instr(&asm_ctx, BWRITERSIO_EXPP, $2.mod, $2.shift, 0, &$3, &$5, 1); |
| } |
| | INSTR_DST omods dreg ',' sregs |
| { |
| TRACE("DST\n"); |
| asm_ctx.funcs->instr(&asm_ctx, BWRITERSIO_DST, $2.mod, $2.shift, 0, &$3, &$5, 2); |
| } |
| | INSTR_LRP omods dreg ',' sregs |
| { |
| TRACE("LRP\n"); |
| asm_ctx.funcs->instr(&asm_ctx, BWRITERSIO_LRP, $2.mod, $2.shift, 0, &$3, &$5, 3); |
| } |
| | INSTR_FRC omods dreg ',' sregs |
| { |
| TRACE("FRC\n"); |
| asm_ctx.funcs->instr(&asm_ctx, BWRITERSIO_FRC, $2.mod, $2.shift, 0, &$3, &$5, 1); |
| } |
| | INSTR_POW omods dreg ',' sregs |
| { |
| TRACE("POW\n"); |
| asm_ctx.funcs->instr(&asm_ctx, BWRITERSIO_POW, $2.mod, $2.shift, 0, &$3, &$5, 2); |
| } |
| | INSTR_CRS omods dreg ',' sregs |
| { |
| TRACE("CRS\n"); |
| asm_ctx.funcs->instr(&asm_ctx, BWRITERSIO_CRS, $2.mod, $2.shift, 0, &$3, &$5, 2); |
| } |
| | INSTR_SGN omods dreg ',' sregs |
| { |
| TRACE("SGN\n"); |
| asm_ctx.funcs->instr(&asm_ctx, BWRITERSIO_SGN, $2.mod, $2.shift, 0, &$3, &$5, 3); |
| } |
| | INSTR_NRM omods dreg ',' sregs |
| { |
| TRACE("NRM\n"); |
| asm_ctx.funcs->instr(&asm_ctx, BWRITERSIO_NRM, $2.mod, $2.shift, 0, &$3, &$5, 1); |
| } |
| | INSTR_SINCOS omods dreg ',' sregs |
| { |
| TRACE("SINCOS\n"); |
| asm_ctx.funcs->instr(&asm_ctx, BWRITERSIO_SINCOS, $2.mod, $2.shift, 0, &$3, &$5, 1); |
| } |
| | INSTR_M4x4 omods dreg ',' sregs |
| { |
| TRACE("M4x4\n"); |
| asm_ctx.funcs->instr(&asm_ctx, BWRITERSIO_M4x4, $2.mod, $2.shift, 0, &$3, &$5, 2); |
| } |
| | INSTR_M4x3 omods dreg ',' sregs |
| { |
| TRACE("M4x3\n"); |
| asm_ctx.funcs->instr(&asm_ctx, BWRITERSIO_M4x3, $2.mod, $2.shift, 0, &$3, &$5, 2); |
| } |
| | INSTR_M3x4 omods dreg ',' sregs |
| { |
| TRACE("M3x4\n"); |
| asm_ctx.funcs->instr(&asm_ctx, BWRITERSIO_M3x4, $2.mod, $2.shift, 0, &$3, &$5, 2); |
| } |
| | INSTR_M3x3 omods dreg ',' sregs |
| { |
| TRACE("M3x3\n"); |
| asm_ctx.funcs->instr(&asm_ctx, BWRITERSIO_M3x3, $2.mod, $2.shift, 0, &$3, &$5, 2); |
| } |
| | INSTR_M3x2 omods dreg ',' sregs |
| { |
| TRACE("M3x2\n"); |
| asm_ctx.funcs->instr(&asm_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"); |
| ZeroMemory(®, sizeof(reg)); |
| reg.type = BWRITERSPR_OUTPUT; |
| reg.regnum = $3; |
| reg.rel_reg = NULL; |
| reg.srcmod = 0; |
| reg.writemask = BWRITERSP_WRITEMASK_ALL; |
| asm_ctx.funcs->dcl_output(&asm_ctx, $2.dclusage, $2.regnum, ®); |
| } |
| | INSTR_DCL dclusage REG_OUTPUT writemask |
| { |
| struct shader_reg reg; |
| TRACE("Output reg declaration\n"); |
| ZeroMemory(®, sizeof(reg)); |
| reg.type = BWRITERSPR_OUTPUT; |
| reg.regnum = $3; |
| reg.rel_reg = NULL; |
| reg.srcmod = 0; |
| reg.writemask = $4; |
| asm_ctx.funcs->dcl_output(&asm_ctx, $2.dclusage, $2.regnum, ®); |
| } |
| | INSTR_DCL dclusage omods dcl_inputreg |
| { |
| struct shader_reg reg; |
| TRACE("Input reg declaration\n"); |
| if($3.shift != 0) { |
| asmparser_message(&asm_ctx, "Line %u: Shift modifier not allowed here\n", |
| asm_ctx.line_no); |
| set_parse_status(&asm_ctx, PARSE_ERR); |
| } |
| ZeroMemory(®, sizeof(reg)); |
| reg.type = $4.type; |
| reg.regnum = $4.regnum; |
| reg.rel_reg = NULL; |
| reg.srcmod = 0; |
| reg.writemask = BWRITERSP_WRITEMASK_ALL; |
| asm_ctx.funcs->dcl_input(&asm_ctx, $2.dclusage, $2.regnum, $3.mod, ®); |
| } |
| | INSTR_DCL dclusage omods dcl_inputreg writemask |
| { |
| struct shader_reg reg; |
| TRACE("Input reg declaration\n"); |
| if($3.shift != 0) { |
| asmparser_message(&asm_ctx, "Line %u: Shift modifier not allowed here\n", |
| asm_ctx.line_no); |
| set_parse_status(&asm_ctx, PARSE_ERR); |
| } |
| ZeroMemory(®, sizeof(reg)); |
| reg.type = $4.type; |
| reg.regnum = $4.regnum; |
| reg.rel_reg = NULL; |
| reg.srcmod = 0; |
| reg.writemask = $5; |
| asm_ctx.funcs->dcl_input(&asm_ctx, $2.dclusage, $2.regnum, $3.mod, ®); |
| } |
| | INSTR_DCL omods dcl_inputreg |
| { |
| struct shader_reg reg; |
| TRACE("Input reg declaration\n"); |
| if($2.shift != 0) { |
| asmparser_message(&asm_ctx, "Line %u: Shift modifier not allowed here\n", |
| asm_ctx.line_no); |
| set_parse_status(&asm_ctx, PARSE_ERR); |
| } |
| ZeroMemory(®, sizeof(reg)); |
| reg.type = $3.type; |
| reg.regnum = $3.regnum; |
| reg.rel_reg = NULL; |
| reg.srcmod = 0; |
| reg.writemask = BWRITERSP_WRITEMASK_ALL; |
| asm_ctx.funcs->dcl_input(&asm_ctx, 0, 0, $2.mod, ®); |
| } |
| | INSTR_DCL omods dcl_inputreg writemask |
| { |
| struct shader_reg reg; |
| TRACE("Input reg declaration\n"); |
| if($2.shift != 0) { |
| asmparser_message(&asm_ctx, "Line %u: Shift modifier not allowed here\n", |
| asm_ctx.line_no); |
| set_parse_status(&asm_ctx, PARSE_ERR); |
| } |
| ZeroMemory(®, sizeof(reg)); |
| reg.type = $3.type; |
| reg.regnum = $3.regnum; |
| reg.rel_reg = NULL; |
| reg.srcmod = 0; |
| reg.writemask = $4; |
| asm_ctx.funcs->dcl_input(&asm_ctx, 0, 0, $2.mod, ®); |
| } |
| | INSTR_DCL sampdcl omods REG_SAMPLER |
| { |
| TRACE("Sampler declared\n"); |
| if($3.shift != 0) { |
| asmparser_message(&asm_ctx, "Line %u: Shift modifier not allowed here\n", |
| asm_ctx.line_no); |
| set_parse_status(&asm_ctx, PARSE_ERR); |
| } |
| asm_ctx.funcs->dcl_sampler(&asm_ctx, $2, $3.mod, $4, asm_ctx.line_no); |
| } |
| | INSTR_DCL sampdcl omods dcl_inputreg |
| { |
| TRACE("Error rule: sampler decl of input reg\n"); |
| asmparser_message(&asm_ctx, "Line %u: Sampler declarations of input regs is not valid\n", |
| asm_ctx.line_no); |
| set_parse_status(&asm_ctx, PARSE_WARN); |
| } |
| | INSTR_DCL sampdcl omods REG_OUTPUT |
| { |
| TRACE("Error rule: sampler decl of output reg\n"); |
| asmparser_message(&asm_ctx, "Line %u: Sampler declarations of output regs is not valid\n", |
| asm_ctx.line_no); |
| set_parse_status(&asm_ctx, PARSE_WARN); |
| } |
| | INSTR_DEF REG_CONSTFLOAT ',' IMMVAL ',' IMMVAL ',' IMMVAL ',' IMMVAL |
| { |
| asm_ctx.funcs->constF(&asm_ctx, $2, $4.val, $6.val, $8.val, $10.val); |
| } |
| | INSTR_DEFI REG_CONSTINT ',' IMMVAL ',' IMMVAL ',' IMMVAL ',' IMMVAL |
| { |
| asm_ctx.funcs->constI(&asm_ctx, $2, $4.val, $6.val, $8.val, $10.val); |
| } |
| | INSTR_DEFB REG_CONSTBOOL ',' IMMBOOL |
| { |
| asm_ctx.funcs->constB(&asm_ctx, $2, $4); |
| } |
| | INSTR_REP sregs |
| { |
| TRACE("REP\n"); |
| asm_ctx.funcs->instr(&asm_ctx, BWRITERSIO_REP, 0, 0, 0, 0, &$2, 1); |
| } |
| | INSTR_ENDREP |
| { |
| TRACE("ENDREP\n"); |
| asm_ctx.funcs->instr(&asm_ctx, BWRITERSIO_ENDREP, 0, 0, 0, 0, 0, 0); |
| } |
| | INSTR_IF sregs |
| { |
| TRACE("IF\n"); |
| asm_ctx.funcs->instr(&asm_ctx, BWRITERSIO_IF, 0, 0, 0, 0, &$2, 1); |
| } |
| | INSTR_IF comp sregs |
| { |
| TRACE("IFC\n"); |
| asm_ctx.funcs->instr(&asm_ctx, BWRITERSIO_IFC, 0, 0, $2, 0, &$3, 2); |
| } |
| | INSTR_ELSE |
| { |
| TRACE("ELSE\n"); |
| asm_ctx.funcs->instr(&asm_ctx, BWRITERSIO_ELSE, 0, 0, 0, 0, 0, 0); |
| } |
| | INSTR_ENDIF |
| { |
| TRACE("ENDIF\n"); |
| asm_ctx.funcs->instr(&asm_ctx, BWRITERSIO_ENDIF, 0, 0, 0, 0, 0, 0); |
| } |
| | INSTR_BREAK |
| { |
| TRACE("BREAK\n"); |
| asm_ctx.funcs->instr(&asm_ctx, BWRITERSIO_BREAK, 0, 0, 0, 0, 0, 0); |
| } |
| | INSTR_BREAK comp sregs |
| { |
| TRACE("BREAKC\n"); |
| asm_ctx.funcs->instr(&asm_ctx, BWRITERSIO_BREAKC, 0, 0, $2, 0, &$3, 2); |
| } |
| | INSTR_BREAKP sregs |
| { |
| TRACE("BREAKP\n"); |
| asm_ctx.funcs->instr(&asm_ctx, BWRITERSIO_BREAKP, 0, 0, 0, 0, &$2, 1); |
| } |
| | INSTR_CALL sregs |
| { |
| TRACE("CALL\n"); |
| asm_ctx.funcs->instr(&asm_ctx, BWRITERSIO_CALL, 0, 0, 0, 0, &$2, 1); |
| } |
| | INSTR_CALLNZ sregs |
| { |
| TRACE("CALLNZ\n"); |
| asm_ctx.funcs->instr(&asm_ctx, BWRITERSIO_CALLNZ, 0, 0, 0, 0, &$2, 2); |
| } |
| | INSTR_LOOP sregs |
| { |
| TRACE("LOOP\n"); |
| asm_ctx.funcs->instr(&asm_ctx, BWRITERSIO_LOOP, 0, 0, 0, 0, &$2, 2); |
| } |
| | INSTR_RET |
| { |
| TRACE("RET\n"); |
| asm_ctx.funcs->instr(&asm_ctx, BWRITERSIO_RET, 0, 0, 0, 0, 0, 0); |
| } |
| | INSTR_ENDLOOP |
| { |
| TRACE("ENDLOOP\n"); |
| asm_ctx.funcs->instr(&asm_ctx, BWRITERSIO_ENDLOOP, 0, 0, 0, 0, 0, 0); |
| } |
| | INSTR_LABEL sregs |
| { |
| TRACE("LABEL\n"); |
| asm_ctx.funcs->instr(&asm_ctx, BWRITERSIO_LABEL, 0, 0, 0, 0, &$2, 1); |
| } |
| | INSTR_SETP comp dreg ',' sregs |
| { |
| TRACE("SETP\n"); |
| asm_ctx.funcs->instr(&asm_ctx, BWRITERSIO_SETP, 0, 0, $2, &$3, &$5, 2); |
| } |
| | INSTR_TEXLDL omods dreg ',' sregs |
| { |
| TRACE("TEXLDL\n"); |
| asm_ctx.funcs->instr(&asm_ctx, BWRITERSIO_TEXLDL, $2.mod, $2.shift, 0, &$3, &$5, 2); |
| } |
| | INSTR_LIT omods dreg ',' sregs |
| { |
| TRACE("LIT\n"); |
| asm_ctx.funcs->instr(&asm_ctx, BWRITERSIO_LIT, $2.mod, $2.shift, 0, &$3, &$5, 1); |
| } |
| | INSTR_MOVA omods dreg ',' sregs |
| { |
| TRACE("MOVA\n"); |
| asm_ctx.funcs->instr(&asm_ctx, BWRITERSIO_MOVA, $2.mod, $2.shift, 0, &$3, &$5, 1); |
| } |
| | INSTR_CMP omods dreg ',' sregs |
| { |
| TRACE("CMP\n"); |
| asm_ctx.funcs->instr(&asm_ctx, BWRITERSIO_CMP, $2.mod, $2.shift, 0, &$3, &$5, 3); |
| } |
| | INSTR_DP2ADD omods dreg ',' sregs |
| { |
| TRACE("DP2ADD\n"); |
| asm_ctx.funcs->instr(&asm_ctx, BWRITERSIO_DP2ADD, $2.mod, $2.shift, 0, &$3, &$5, 3); |
| } |
| | INSTR_TEXKILL dreg |
| { |
| TRACE("TEXKILL\n"); |
| asm_ctx.funcs->instr(&asm_ctx, BWRITERSIO_TEXKILL, 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 */ |
| asm_ctx.funcs->instr(&asm_ctx, BWRITERSIO_TEX, $2.mod, $2.shift, 0, &$3, &$5, 2); |
| } |
| | INSTR_TEXLDP omods dreg ',' sregs |
| { |
| TRACE("TEXLDP\n"); |
| asm_ctx.funcs->instr(&asm_ctx, BWRITERSIO_TEXLDP, $2.mod, $2.shift, 0, &$3, &$5, 2); |
| } |
| | INSTR_TEXLDB omods dreg ',' sregs |
| { |
| TRACE("TEXLDB\n"); |
| asm_ctx.funcs->instr(&asm_ctx, BWRITERSIO_TEXLDB, $2.mod, $2.shift, 0, &$3, &$5, 2); |
| } |
| | INSTR_DSX omods dreg ',' sregs |
| { |
| TRACE("DSX\n"); |
| asm_ctx.funcs->instr(&asm_ctx, BWRITERSIO_DSX, $2.mod, $2.shift, 0, &$3, &$5, 1); |
| } |
| | INSTR_DSY omods dreg ',' sregs |
| { |
| TRACE("DSY\n"); |
| asm_ctx.funcs->instr(&asm_ctx, BWRITERSIO_DSY, $2.mod, $2.shift, 0, &$3, &$5, 1); |
| } |
| | INSTR_TEXLDD omods dreg ',' sregs |
| { |
| TRACE("TEXLDD\n"); |
| asm_ctx.funcs->instr(&asm_ctx, BWRITERSIO_TEXLDD, $2.mod, $2.shift, 0, &$3, &$5, 4); |
| } |
| |
| 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 |
| { |
| $$.regnum = $1; $$.type = BWRITERSPR_INPUT; |
| } |
| | REG_CONSTFLOAT |
| { |
| asmparser_message(&asm_ctx, "Line %u: Register c%u is not a valid destination register\n", |
| asm_ctx.line_no, $1); |
| set_parse_status(&asm_ctx, PARSE_WARN); |
| } |
| | REG_CONSTINT |
| { |
| asmparser_message(&asm_ctx, "Line %u: Register i%u is not a valid destination register\n", |
| asm_ctx.line_no, $1); |
| set_parse_status(&asm_ctx, PARSE_WARN); |
| } |
| | REG_CONSTBOOL |
| { |
| asmparser_message(&asm_ctx, "Line %u: Register b%u is not a valid destination register\n", |
| asm_ctx.line_no, $1); |
| set_parse_status(&asm_ctx, PARSE_WARN); |
| } |
| | REG_TEXTURE |
| { |
| $$.regnum = $1; $$.type = BWRITERSPR_TEXTURE; |
| } |
| | REG_TEXCRDOUT |
| { |
| $$.regnum = $1; $$.type = BWRITERSPR_TEXCRDOUT; |
| } |
| | REG_SAMPLER |
| { |
| asmparser_message(&asm_ctx, "Line %u: Register s%u is not a valid destination register\n", |
| asm_ctx.line_no, $1); |
| set_parse_status(&asm_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(&asm_ctx, "Line %u: Register vPos is not a valid destination register\n", |
| asm_ctx.line_no); |
| set_parse_status(&asm_ctx, PARSE_WARN); |
| } |
| | REG_VFACE |
| { |
| asmparser_message(&asm_ctx, "Line %u: Register vFace is not a valid destination register\n", |
| asm_ctx.line_no); |
| set_parse_status(&asm_ctx, PARSE_WARN); |
| } |
| | REG_ADDRESS |
| { |
| /* index 0 is hardcoded for the addr register */ |
| $$.regnum = 0; $$.type = BWRITERSPR_ADDR; |
| } |
| | REG_LOOP |
| { |
| asmparser_message(&asm_ctx, "Line %u: Register aL is not a valid destination register\n", |
| asm_ctx.line_no); |
| set_parse_status(&asm_ctx, PARSE_WARN); |
| } |
| |
| writemask: '.' wm_components |
| { |
| if($2.writemask == SWIZZLE_ERR) { |
| asmparser_message(&asm_ctx, "Line %u: Invalid writemask specified\n", |
| asm_ctx.line_no); |
| set_parse_status(&asm_ctx, PARSE_ERR); |
| /* Provide a correct writemask to prevent following complaints */ |
| $$ = BWRITERSP_WRITEMASK_ALL; |
| } |
| else { |
| $$ = $2.writemask; |
| TRACE("Writemask: %x\n", $$); |
| } |
| } |
| |
| wm_components: COMPONENT |
| { |
| $$.writemask = 1 << $1; |
| $$.last = $1; |
| $$.idx = 1; |
| } |
| | wm_components COMPONENT |
| { |
| if($1.writemask == SWIZZLE_ERR || $1.idx == 4) |
| /* Wrong writemask */ |
| $$.writemask = SWIZZLE_ERR; |
| else { |
| if($2 <= $1.last) |
| $$.writemask = SWIZZLE_ERR; |
| else { |
| $$.writemask = $1.writemask | (1 << $2); |
| $$.idx = $1.idx + 1; |
| } |
| } |
| } |
| |
| swizzle: /* empty */ |
| { |
| $$ = BWRITERVS_NOSWIZZLE; |
| TRACE("Default swizzle: %08x\n", $$); |
| } |
| | '.' sw_components |
| { |
| if($2.swizzle == SWIZZLE_ERR) { |
| asmparser_message(&asm_ctx, "Line %u: Invalid swizzle\n", |
| asm_ctx.line_no); |
| set_parse_status(&asm_ctx, PARSE_ERR); |
| /* Provide a correct swizzle to prevent following complaints */ |
| $$ = BWRITERVS_NOSWIZZLE; |
| } |
| else { |
| DWORD last, i; |
| |
| $$ = $2.swizzle << BWRITERVS_SWIZZLE_SHIFT; |
| /* Fill the swizzle by extending the last component */ |
| last = ($2.swizzle >> 2 * ($2.idx - 1)) & 0x03; |
| for(i = $2.idx; i < 4; i++){ |
| $$ |= last << (BWRITERVS_SWIZZLE_SHIFT + 2 * i); |
| } |
| TRACE("Got a swizzle: %08x\n", $$); |
| } |
| } |
| |
| sw_components: COMPONENT |
| { |
| $$.swizzle = $1; |
| $$.idx = 1; |
| } |
| | sw_components COMPONENT |
| { |
| if($1.idx == 4) { |
| /* Too many sw_components */ |
| $$.swizzle = SWIZZLE_ERR; |
| $$.idx = 4; |
| } |
| else { |
| $$.swizzle = $1.swizzle | ($2 << 2 * $1.idx); |
| $$.idx = $1.idx + 1; |
| } |
| } |
| |
| omods: /* Empty */ |
| { |
| $$.mod = 0; |
| $$.shift = 0; |
| } |
| | omods omodifier |
| { |
| $$.mod = $1.mod | $2.mod; |
| if($1.shift && $2.shift) { |
| asmparser_message(&asm_ctx, "Line %u: More than one shift flag\n", |
| asm_ctx.line_no); |
| set_parse_status(&asm_ctx, PARSE_ERR); |
| $$.shift = $1.shift; |
| } else { |
| $$.shift = $1.shift | $2.shift; |
| } |
| } |
| |
| omodifier: 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(&asm_ctx, "Line %u: Too many source registers in this instruction\n", |
| asm_ctx.line_no); |
| set_parse_status(&asm_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_ABS: $$.srcmod = BWRITERSPSM_ABSNEG; break; |
| default: |
| FIXME("Unhandled combination of NEGATE and %u\n", $4); |
| } |
| $$.swizzle = $5; |
| } |
| | 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(&asm_ctx, "Line %u: Unexpected float %f\n", |
| asm_ctx.line_no, $1.val); |
| set_parse_status(&asm_ctx, PARSE_ERR); |
| } |
| $$.val = $1.val; |
| } |
| | immsum '+' IMMVAL |
| { |
| if(!$3.integer) { |
| asmparser_message(&asm_ctx, "Line %u: Unexpected float %f\n", |
| asm_ctx.line_no, $3.val); |
| set_parse_status(&asm_ctx, PARSE_ERR); |
| } |
| $$.val = $1.val + $3.val; |
| } |
| |
| smod: 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(&asm_ctx, "Line %u: Register o%u is not a valid source register\n", |
| asm_ctx.line_no, $1); |
| set_parse_status(&asm_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(&asm_ctx, "Line %u: Register oT%u is not a valid source register\n", |
| asm_ctx.line_no, $1); |
| set_parse_status(&asm_ctx, PARSE_WARN); |
| } |
| | REG_SAMPLER |
| { |
| $$.regnum = $1; $$.type = BWRITERSPR_SAMPLER; |
| } |
| | REG_OPOS |
| { |
| asmparser_message(&asm_ctx, "Line %u: Register oPos is not a valid source register\n", |
| asm_ctx.line_no); |
| set_parse_status(&asm_ctx, PARSE_WARN); |
| } |
| | REG_OFOG |
| { |
| asmparser_message(&asm_ctx, "Line %u: Register oFog is not a valid source register\n", |
| asm_ctx.line_no); |
| set_parse_status(&asm_ctx, PARSE_WARN); |
| } |
| | REG_VERTEXCOLOR |
| { |
| asmparser_message(&asm_ctx, "Line %u: Register oD%u is not a valid source register\n", |
| asm_ctx.line_no, $1); |
| set_parse_status(&asm_ctx, PARSE_WARN); |
| } |
| | REG_FRAGCOLOR |
| { |
| asmparser_message(&asm_ctx, "Line %u: Register oC%u is not a valid source register\n", |
| asm_ctx.line_no, $1); |
| set_parse_status(&asm_ctx, PARSE_WARN); |
| } |
| | REG_FRAGDEPTH |
| { |
| asmparser_message(&asm_ctx, "Line %u: Register oDepth is not a valid source register\n", |
| asm_ctx.line_no); |
| set_parse_status(&asm_ctx, PARSE_WARN); |
| } |
| | REG_PREDICATE |
| { |
| $$.regnum = 0; $$.type = BWRITERSPR_PREDICATE; |
| } |
| | REG_VPOS |
| { |
| $$.regnum = 0; $$.type = BWRITERSPR_MISCTYPE; |
| } |
| | REG_VFACE |
| { |
| $$.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; |
| } |
| |
| 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; |
| } |
| |
| dcl_inputreg: REG_INPUT |
| { |
| $$.regnum = $1; $$.type = BWRITERSPR_INPUT; |
| } |
| | REG_TEXTURE |
| { |
| $$.regnum = $1; $$.type = BWRITERSPR_TEXTURE; |
| } |
| |
| 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 (char const *s) { |
| asmparser_message(&asm_ctx, "Line %u: Error \"%s\" from bison\n", asm_ctx.line_no, s); |
| set_parse_status(&asm_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 worst 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(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(); |
| |
| 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; |
| } |