/* * 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 "d3dcompiler_private.h" #include "asmshader.tab.h" WINE_DEFAULT_DEBUG_CHANNEL(asmshader); %} %option noyywrap %option prefix="asmshader_" %option noinput nounput never-interactive /* 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. */ DOT \. COMPONENT [xyzw]|[rgba] /* 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 oD[01] 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; } 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} { asmshader_lval.regnum = atoi(yytext + 1); return REG_TEMP; } {REG_OUTPUT} { asmshader_lval.regnum = atoi(yytext + 1); return REG_OUTPUT; } {REG_INPUT} { asmshader_lval.regnum = atoi(yytext + 1); return REG_INPUT; } {REG_CONSTFLOAT} { asmshader_lval.regnum = atoi(yytext + 1); return REG_CONSTFLOAT; } {REG_CONSTINT} { asmshader_lval.regnum = atoi(yytext + 1); return REG_CONSTINT; } {REG_CONSTBOOL} { asmshader_lval.regnum = atoi(yytext + 1); return REG_CONSTBOOL; } {REG_TEXTURE} { asmshader_lval.regnum = atoi(yytext + 1); return REG_TEXTURE; } {REG_TEXCRDOUT} { asmshader_lval.regnum = atoi(yytext + 2); return REG_TEXCRDOUT; } {REG_SAMPLER} { asmshader_lval.regnum = atoi(yytext + 1); return REG_SAMPLER; } {REG_OPOS} {return REG_OPOS; } {REG_OFOG} {return REG_OFOG; } {REG_OPTS} {return REG_OPTS; } {REG_VERTEXCOLOR} { asmshader_lval.regnum = atoi(yytext + 2); return REG_VERTEXCOLOR; } {REG_FRAGCOLOR} { asmshader_lval.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} { asmshader_lval.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|vs_2_0 {return VER_VS20; } vs\.2\.x|vs_2_x {return VER_VS2X; } vs\.3\.0|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|ps_2_0 {return VER_PS20; } ps\.2\.x|ps_2_x {return VER_PS2X; } ps\.3\.0|ps_3_0 {return VER_PS30; } {DOT} {return yytext[0]; } {COMPONENT} { switch(yytext[0]) { case 'x': case 'r': asmshader_lval.component = 0; break; case 'y': case 'g': asmshader_lval.component = 1; break; case 'z': case 'b': asmshader_lval.component = 2; break; case 'w': case 'a': asmshader_lval.component = 3; break; } return COMPONENT; } /* 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} { asmshader_lval.immval.val = atof(yytext); asmshader_lval.immval.integer = ((strstr(yytext, ".") == NULL) && (strstr(yytext, "f") == NULL)); return IMMVAL; } true { asmshader_lval.immbool = TRUE; return IMMBOOL; } false { asmshader_lval.immbool = FALSE; return IMMBOOL; } {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') { asmshader_lval.regnum = 0; } else { asmshader_lval.regnum = atoi(yytext + strlen("_position")); } return USAGE_POSITION; } {DCL_BLENDWEIGHT} { if(yytext[strlen("_blendweight")] == '\0') { asmshader_lval.regnum = 0; } else { asmshader_lval.regnum = atoi(yytext + strlen("_blendweight")); } return USAGE_BLENDWEIGHT; } {DCL_BLENDINDICES} { if(yytext[strlen("_blendindices")] == '\0') { asmshader_lval.regnum = 0; } else { asmshader_lval.regnum = atoi(yytext + strlen("_blendindices")); } return USAGE_BLENDINDICES; } {DCL_NORMAL} { if(yytext[strlen("_normal")] == '\0') { asmshader_lval.regnum = 0; } else { asmshader_lval.regnum = atoi(yytext + strlen("_normal")); } return USAGE_NORMAL; } {DCL_PSIZE} { if(yytext[strlen("_psize")] == '\0') { asmshader_lval.regnum = 0; } else { asmshader_lval.regnum = atoi(yytext + strlen("_psize")); } return USAGE_PSIZE; } {DCL_TEXCOORD} { if(yytext[strlen("_texcoord")] == '\0') { asmshader_lval.regnum = 0; } else { asmshader_lval.regnum = atoi(yytext + strlen("_texcoord")); } return USAGE_TEXCOORD; } {DCL_TANGENT} { if(yytext[strlen("_tangent")] == '\0') { asmshader_lval.regnum = 0; } else { asmshader_lval.regnum = atoi(yytext + strlen("_tangent")); } return USAGE_TANGENT; } {DCL_BINORMAL} { if(yytext[strlen("_binormal")] == '\0') { asmshader_lval.regnum = 0; } else { asmshader_lval.regnum = atoi(yytext + strlen("_binormal")); } return USAGE_BINORMAL; } {DCL_TESSFACTOR} { if(yytext[strlen("_tessfactor")] == '\0') { asmshader_lval.regnum = 0; } else { asmshader_lval.regnum = atoi(yytext + strlen("_tessfactor")); } return USAGE_TESSFACTOR; } {DCL_POSITIONT} { if(yytext[strlen("_positiont")] == '\0') { asmshader_lval.regnum = 0; } else { asmshader_lval.regnum = atoi(yytext + strlen("_positiont")); } return USAGE_POSITIONT; } {DCL_COLOR} { if(yytext[strlen("_color")] == '\0') { asmshader_lval.regnum = 0; } else { asmshader_lval.regnum = atoi(yytext + strlen("_color")); } return USAGE_COLOR; } {DCL_FOG} { if(yytext[strlen("_fog")] == '\0') { asmshader_lval.regnum = 0; } else { asmshader_lval.regnum = atoi(yytext + strlen("_fog")); } return USAGE_FOG; } {DCL_DEPTH} { if(yytext[strlen("_depth")] == '\0') { asmshader_lval.regnum = 0; } else { asmshader_lval.regnum = atoi(yytext + strlen("_depth")); } return USAGE_DEPTH; } {DCL_SAMPLE} { if(yytext[strlen("_sample")] == '\0') { asmshader_lval.regnum = 0; } else { asmshader_lval.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} { asm_ctx.line_no++; } {ANY} { asmparser_message(&asm_ctx, "Line %u: Unexpected input %s\n", asm_ctx.line_no, yytext); set_parse_status(&asm_ctx.status, PARSE_ERR); } %% struct bwriter_shader *SlAssembleShader(const char *text, char **messages) { struct bwriter_shader *ret = NULL; YY_BUFFER_STATE buffer; TRACE("%p, %p\n", text, messages); buffer = asmshader__scan_string(text); asmshader__switch_to_buffer(buffer); ret = parse_asm_shader(messages); asmshader__delete_buffer(buffer); return ret; }