shlwapi: URL_FILE_USE_PATHURL flag only unescapes file urls in UrlCanonicalize.
[wine] / dlls / d3dx9_36 / asmshader.y
1 /*
2  * Direct3D shader assembler
3  *
4  * Copyright 2008 Stefan Dösinger
5  * Copyright 2009 Matteo Bruni
6  *
7  * This library is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Lesser General Public
9  * License as published by the Free Software Foundation; either
10  * version 2.1 of the License, or (at your option) any later version.
11  *
12  * This library is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * Lesser General Public License for more details.
16  *
17  * You should have received a copy of the GNU Lesser General Public
18  * License along with this library; if not, write to the Free Software
19  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
20  */
21
22 %{
23 #include "config.h"
24 #include "wine/port.h"
25 #include "wine/debug.h"
26
27 #include "d3dx9_36_private.h"
28
29 #include <stdio.h>
30
31 WINE_DEFAULT_DEBUG_CHANNEL(asmshader);
32
33 struct asm_parser asm_ctx;
34
35 /* Needed lexer functions declarations */
36 void asmshader_error(const char *s);
37 int asmshader_lex(void);
38
39 void set_rel_reg(struct shader_reg *reg, struct rel_reg *rel) {
40     /* We can have an additional offset without true relative addressing
41      * ex. c2[ 4 ] */
42     reg->regnum += rel->additional_offset;
43     if(!rel->has_rel_reg) {
44         reg->rel_reg = NULL;
45     } else {
46         reg->rel_reg = asm_alloc(sizeof(*reg->rel_reg));
47         if(!reg->rel_reg) {
48             return;
49         }
50         reg->rel_reg->type = rel->type;
51         reg->rel_reg->swizzle = rel->swizzle;
52         reg->rel_reg->regnum = rel->rel_regnum;
53     }
54 }
55
56 %}
57
58 %union {
59     struct {
60         float           val;
61         BOOL            integer;
62     } immval;
63     BOOL                immbool;
64     unsigned int        regnum;
65     struct shader_reg   reg;
66     DWORD               srcmod;
67     DWORD               writemask;
68     struct {
69         DWORD           writemask;
70         DWORD           idx;
71         DWORD           last;
72     } wm_components;
73     DWORD               swizzle;
74     struct {
75         DWORD           swizzle;
76         DWORD           idx;
77     } sw_components;
78     DWORD               component;
79     struct {
80         DWORD           mod;
81         DWORD           shift;
82     } modshift;
83     BWRITER_COMPARISON_TYPE comptype;
84     struct {
85         DWORD           dclusage;
86         unsigned int    regnum;
87     } declaration;
88     BWRITERSAMPLER_TEXTURE_TYPE samplertype;
89     struct rel_reg      rel_reg;
90     struct src_regs     sregs;
91 }
92
93 /* Common instructions between vertex and pixel shaders */
94 %token INSTR_ADD
95 %token INSTR_NOP
96 %token INSTR_MOV
97 %token INSTR_SUB
98 %token INSTR_MAD
99 %token INSTR_MUL
100 %token INSTR_RCP
101 %token INSTR_RSQ
102 %token INSTR_DP3
103 %token INSTR_DP4
104 %token INSTR_MIN
105 %token INSTR_MAX
106 %token INSTR_SLT
107 %token INSTR_SGE
108 %token INSTR_ABS
109 %token INSTR_EXP
110 %token INSTR_LOG
111 %token INSTR_EXPP
112 %token INSTR_LOGP
113 %token INSTR_DST
114 %token INSTR_LRP
115 %token INSTR_FRC
116 %token INSTR_POW
117 %token INSTR_CRS
118 %token INSTR_SGN
119 %token INSTR_NRM
120 %token INSTR_SINCOS
121 %token INSTR_M4x4
122 %token INSTR_M4x3
123 %token INSTR_M3x4
124 %token INSTR_M3x3
125 %token INSTR_M3x2
126 %token INSTR_DCL
127 %token INSTR_DEF
128 %token INSTR_DEFB
129 %token INSTR_DEFI
130 %token INSTR_REP
131 %token INSTR_ENDREP
132 %token INSTR_IF
133 %token INSTR_ELSE
134 %token INSTR_ENDIF
135 %token INSTR_BREAK
136 %token INSTR_BREAKP
137 %token INSTR_CALL
138 %token INSTR_CALLNZ
139 %token INSTR_LOOP
140 %token INSTR_RET
141 %token INSTR_ENDLOOP
142 %token INSTR_LABEL
143 %token INSTR_SETP
144 %token INSTR_TEXLDL
145
146 /* Vertex shader only instructions  */
147 %token INSTR_LIT
148 %token INSTR_MOVA
149
150 /* Pixel shader only instructions   */
151 %token INSTR_CMP
152 %token INSTR_DP2ADD
153 %token INSTR_TEXKILL
154 %token INSTR_TEXLD
155 %token INSTR_DSX
156 %token INSTR_DSY
157 %token INSTR_TEXLDP
158 %token INSTR_TEXLDB
159 %token INSTR_TEXLDD
160
161 /* Registers */
162 %token <regnum> REG_TEMP
163 %token <regnum> REG_OUTPUT
164 %token <regnum> REG_INPUT
165 %token <regnum> REG_CONSTFLOAT
166 %token <regnum> REG_CONSTINT
167 %token <regnum> REG_CONSTBOOL
168 %token <regnum> REG_TEXTURE
169 %token <regnum> REG_SAMPLER
170 %token <regnum> REG_TEXCRDOUT
171 %token REG_OPOS
172 %token REG_OFOG
173 %token REG_OPTS
174 %token <regnum> REG_VERTEXCOLOR
175 %token <regnum> REG_FRAGCOLOR
176 %token REG_FRAGDEPTH
177 %token REG_VPOS
178 %token REG_VFACE
179 %token REG_ADDRESS
180 %token REG_LOOP
181 %token REG_PREDICATE
182 %token <regnum> REG_LABEL
183
184 /* Version tokens */
185 %token VER_VS10
186 %token VER_VS11
187 %token VER_VS20
188 %token VER_VS2X
189 %token VER_VS30
190
191 %token VER_PS10
192 %token VER_PS11
193 %token VER_PS12
194 %token VER_PS13
195 %token VER_PS14
196 %token VER_PS20
197 %token VER_PS2X
198 %token VER_PS30
199
200 /* Output modifiers */
201 %token MOD_SAT
202 %token MOD_PP
203 %token MOD_CENTROID
204
205 /* Compare tokens */
206 %token COMP_GT
207 %token COMP_LT
208 %token COMP_GE
209 %token COMP_LE
210 %token COMP_EQ
211 %token COMP_NE
212
213 /* Source register modifiers */
214 %token SMOD_ABS
215 %token SMOD_NOT
216
217 /* Sampler types */
218 %token SAMPTYPE_1D
219 %token SAMPTYPE_2D
220 %token SAMPTYPE_CUBE
221 %token SAMPTYPE_VOLUME
222
223 /* Usage declaration tokens */
224 %token <regnum> USAGE_POSITION
225 %token <regnum> USAGE_BLENDWEIGHT
226 %token <regnum> USAGE_BLENDINDICES
227 %token <regnum> USAGE_NORMAL
228 %token <regnum> USAGE_PSIZE
229 %token <regnum> USAGE_TEXCOORD
230 %token <regnum> USAGE_TANGENT
231 %token <regnum> USAGE_BINORMAL
232 %token <regnum> USAGE_TESSFACTOR
233 %token <regnum> USAGE_POSITIONT
234 %token <regnum> USAGE_COLOR
235 %token <regnum> USAGE_FOG
236 %token <regnum> USAGE_DEPTH
237 %token <regnum> USAGE_SAMPLE
238
239 /* Misc stuff */
240 %token <component> COMPONENT
241 %token <immval> IMMVAL
242 %token <immbool> IMMBOOL
243
244 %type <reg> dreg_name
245 %type <reg> dreg
246 %type <reg> sreg_name
247 %type <reg> relreg_name
248 %type <reg> sreg
249 %type <srcmod> smod
250 %type <writemask> writemask
251 %type <wm_components> wm_components
252 %type <swizzle> swizzle
253 %type <sw_components> sw_components
254 %type <modshift> omods
255 %type <modshift> omodifier
256 %type <comptype> comp
257 %type <declaration> dclusage
258 %type <reg> dcl_inputreg
259 %type <samplertype> sampdcl
260 %type <rel_reg> rel_reg
261 %type <reg> predicate
262 %type <immval> immsum
263 %type <sregs> sregs
264
265 %%
266
267 shader:               version_marker instructions
268                         {
269                             asm_ctx.funcs->end(&asm_ctx);
270                         }
271
272 version_marker:       VER_VS10
273                         {
274                             TRACE("Vertex shader 1.0\n");
275                             create_vs10_parser(&asm_ctx);
276                         }
277                     | VER_VS11
278                         {
279                             TRACE("Vertex shader 1.1\n");
280                             create_vs11_parser(&asm_ctx);
281                         }
282                     | VER_VS20
283                         {
284                             TRACE("Vertex shader 2.0\n");
285                             create_vs20_parser(&asm_ctx);
286                         }
287                     | VER_VS2X
288                         {
289                             TRACE("Vertex shader 2.x\n");
290                             create_vs2x_parser(&asm_ctx);
291                         }
292                     | VER_VS30
293                         {
294                             TRACE("Vertex shader 3.0\n");
295                             create_vs30_parser(&asm_ctx);
296                         }
297                     | VER_PS10
298                         {
299                             TRACE("Pixel  shader 1.0\n");
300                             set_parse_status(&asm_ctx, PARSE_ERR);
301                             YYABORT;
302                         }
303                     | VER_PS11
304                         {
305                             TRACE("Pixel  shader 1.1\n");
306                             set_parse_status(&asm_ctx, PARSE_ERR);
307                             YYABORT;
308                         }
309                     | VER_PS12
310                         {
311                             TRACE("Pixel  shader 1.2\n");
312                             set_parse_status(&asm_ctx, PARSE_ERR);
313                             YYABORT;
314                         }
315                     | VER_PS13
316                         {
317                             TRACE("Pixel  shader 1.3\n");
318                             set_parse_status(&asm_ctx, PARSE_ERR);
319                             YYABORT;
320                         }
321                     | VER_PS14
322                         {
323                             TRACE("Pixel  shader 1.4\n");
324                             set_parse_status(&asm_ctx, PARSE_ERR);
325                             YYABORT;
326                         }
327                     | VER_PS20
328                         {
329                             TRACE("Pixel  shader 2.0\n");
330                             create_ps20_parser(&asm_ctx);
331                         }
332                     | VER_PS2X
333                         {
334                             TRACE("Pixel  shader 2.x\n");
335                             create_ps2x_parser(&asm_ctx);
336                         }
337                     | VER_PS30
338                         {
339                             TRACE("Pixel  shader 3.0\n");
340                             create_ps30_parser(&asm_ctx);
341                         }
342
343 instructions:         /* empty */
344                     | instructions complexinstr
345                             {
346                                 /* Nothing to do */
347                             }
348
349 complexinstr:         instruction
350                             {
351
352                             }
353                     | predicate instruction
354                             {
355                                 TRACE("predicate\n");
356                                 asm_ctx.funcs->predicate(&asm_ctx, &$1);
357                             }
358
359 instruction:          INSTR_ADD omods dreg ',' sregs
360                             {
361                                 TRACE("ADD\n");
362                                 asm_ctx.funcs->instr(&asm_ctx, BWRITERSIO_ADD, $2.mod, $2.shift, 0, &$3, &$5, 2);
363                             }
364                     | INSTR_NOP
365                             {
366                                 TRACE("NOP\n");
367                                 asm_ctx.funcs->instr(&asm_ctx, BWRITERSIO_NOP, 0, 0, 0, 0, 0, 0);
368                             }
369                     | INSTR_MOV omods dreg ',' sregs
370                             {
371                                 TRACE("MOV\n");
372                                 asm_ctx.funcs->instr(&asm_ctx, BWRITERSIO_MOV, $2.mod, $2.shift, 0, &$3, &$5, 1);
373                             }
374                     | INSTR_SUB omods dreg ',' sregs
375                             {
376                                 TRACE("SUB\n");
377                                 asm_ctx.funcs->instr(&asm_ctx, BWRITERSIO_SUB, $2.mod, $2.shift, 0, &$3, &$5, 2);
378                             }
379                     | INSTR_MAD omods dreg ',' sregs
380                             {
381                                 TRACE("MAD\n");
382                                 asm_ctx.funcs->instr(&asm_ctx, BWRITERSIO_MAD, $2.mod, $2.shift, 0, &$3, &$5, 3);
383                             }
384                     | INSTR_MUL omods dreg ',' sregs
385                             {
386                                 TRACE("MUL\n");
387                                 asm_ctx.funcs->instr(&asm_ctx, BWRITERSIO_MUL, $2.mod, $2.shift, 0, &$3, &$5, 2);
388                             }
389                     | INSTR_RCP omods dreg ',' sregs
390                             {
391                                 TRACE("RCP\n");
392                                 asm_ctx.funcs->instr(&asm_ctx, BWRITERSIO_RCP, $2.mod, $2.shift, 0, &$3, &$5, 1);
393                             }
394                     | INSTR_RSQ omods dreg ',' sregs
395                             {
396                                 TRACE("RSQ\n");
397                                 asm_ctx.funcs->instr(&asm_ctx, BWRITERSIO_RSQ, $2.mod, $2.shift, 0, &$3, &$5, 1);
398                             }
399                     | INSTR_DP3 omods dreg ',' sregs
400                             {
401                                 TRACE("DP3\n");
402                                 asm_ctx.funcs->instr(&asm_ctx, BWRITERSIO_DP3, $2.mod, $2.shift, 0, &$3, &$5, 2);
403                             }
404                     | INSTR_DP4 omods dreg ',' sregs
405                             {
406                                 TRACE("DP4\n");
407                                 asm_ctx.funcs->instr(&asm_ctx, BWRITERSIO_DP4, $2.mod, $2.shift, 0, &$3, &$5, 2);
408                             }
409                     | INSTR_MIN omods dreg ',' sregs
410                             {
411                                 TRACE("MIN\n");
412                                 asm_ctx.funcs->instr(&asm_ctx, BWRITERSIO_MIN, $2.mod, $2.shift, 0, &$3, &$5, 2);
413                             }
414                     | INSTR_MAX omods dreg ',' sregs
415                             {
416                                 TRACE("MAX\n");
417                                 asm_ctx.funcs->instr(&asm_ctx, BWRITERSIO_MAX, $2.mod, $2.shift, 0, &$3, &$5, 2);
418                             }
419                     | INSTR_SLT omods dreg ',' sregs
420                             {
421                                 TRACE("SLT\n");
422                                 asm_ctx.funcs->instr(&asm_ctx, BWRITERSIO_SLT, $2.mod, $2.shift, 0, &$3, &$5, 2);
423                             }
424                     | INSTR_SGE omods dreg ',' sregs
425                             {
426                                 TRACE("SGE\n");
427                                 asm_ctx.funcs->instr(&asm_ctx, BWRITERSIO_SGE, $2.mod, $2.shift, 0, &$3, &$5, 2);
428                             }
429                     | INSTR_ABS omods dreg ',' sregs
430                             {
431                                 TRACE("ABS\n");
432                                 asm_ctx.funcs->instr(&asm_ctx, BWRITERSIO_ABS, $2.mod, $2.shift, 0, &$3, &$5, 1);
433                             }
434                     | INSTR_EXP omods dreg ',' sregs
435                             {
436                                 TRACE("EXP\n");
437                                 asm_ctx.funcs->instr(&asm_ctx, BWRITERSIO_EXP, $2.mod, $2.shift, 0, &$3, &$5, 1);
438                             }
439                     | INSTR_LOG omods dreg ',' sregs
440                             {
441                                 TRACE("LOG\n");
442                                 asm_ctx.funcs->instr(&asm_ctx, BWRITERSIO_LOG, $2.mod, $2.shift, 0, &$3, &$5, 1);
443                             }
444                     | INSTR_LOGP omods dreg ',' sregs
445                             {
446                                 TRACE("LOGP\n");
447                                 asm_ctx.funcs->instr(&asm_ctx, BWRITERSIO_LOGP, $2.mod, $2.shift, 0, &$3, &$5, 1);
448                             }
449                     | INSTR_EXPP omods dreg ',' sregs
450                             {
451                                 TRACE("EXPP\n");
452                                 asm_ctx.funcs->instr(&asm_ctx, BWRITERSIO_EXPP, $2.mod, $2.shift, 0, &$3, &$5, 1);
453                             }
454                     | INSTR_DST omods dreg ',' sregs
455                             {
456                                 TRACE("DST\n");
457                                 asm_ctx.funcs->instr(&asm_ctx, BWRITERSIO_DST, $2.mod, $2.shift, 0, &$3, &$5, 2);
458                             }
459                     | INSTR_LRP omods dreg ',' sregs
460                             {
461                                 TRACE("LRP\n");
462                                 asm_ctx.funcs->instr(&asm_ctx, BWRITERSIO_LRP, $2.mod, $2.shift, 0, &$3, &$5, 3);
463                             }
464                     | INSTR_FRC omods dreg ',' sregs
465                             {
466                                 TRACE("FRC\n");
467                                 asm_ctx.funcs->instr(&asm_ctx, BWRITERSIO_FRC, $2.mod, $2.shift, 0, &$3, &$5, 1);
468                             }
469                     | INSTR_POW omods dreg ',' sregs
470                             {
471                                 TRACE("POW\n");
472                                 asm_ctx.funcs->instr(&asm_ctx, BWRITERSIO_POW, $2.mod, $2.shift, 0, &$3, &$5, 2);
473                             }
474                     | INSTR_CRS omods dreg ',' sregs
475                             {
476                                 TRACE("CRS\n");
477                                 asm_ctx.funcs->instr(&asm_ctx, BWRITERSIO_CRS, $2.mod, $2.shift, 0, &$3, &$5, 2);
478                             }
479                     | INSTR_SGN omods dreg ',' sregs
480                             {
481                                 TRACE("SGN\n");
482                                 asm_ctx.funcs->instr(&asm_ctx, BWRITERSIO_SGN, $2.mod, $2.shift, 0, &$3, &$5, 3);
483                             }
484                     | INSTR_NRM omods dreg ',' sregs
485                             {
486                                 TRACE("NRM\n");
487                                 asm_ctx.funcs->instr(&asm_ctx, BWRITERSIO_NRM, $2.mod, $2.shift, 0, &$3, &$5, 1);
488                             }
489                     | INSTR_SINCOS omods dreg ',' sregs
490                             {
491                                 TRACE("SINCOS\n");
492                                 asm_ctx.funcs->instr(&asm_ctx, BWRITERSIO_SINCOS, $2.mod, $2.shift, 0, &$3, &$5, 1);
493                             }
494                     | INSTR_M4x4 omods dreg ',' sregs
495                             {
496                                 TRACE("M4x4\n");
497                                 asm_ctx.funcs->instr(&asm_ctx, BWRITERSIO_M4x4, $2.mod, $2.shift, 0, &$3, &$5, 2);
498                             }
499                     | INSTR_M4x3 omods dreg ',' sregs
500                             {
501                                 TRACE("M4x3\n");
502                                 asm_ctx.funcs->instr(&asm_ctx, BWRITERSIO_M4x3, $2.mod, $2.shift, 0, &$3, &$5, 2);
503                             }
504                     | INSTR_M3x4 omods dreg ',' sregs
505                             {
506                                 TRACE("M3x4\n");
507                                 asm_ctx.funcs->instr(&asm_ctx, BWRITERSIO_M3x4, $2.mod, $2.shift, 0, &$3, &$5, 2);
508                             }
509                     | INSTR_M3x3 omods dreg ',' sregs
510                             {
511                                 TRACE("M3x3\n");
512                                 asm_ctx.funcs->instr(&asm_ctx, BWRITERSIO_M3x3, $2.mod, $2.shift, 0, &$3, &$5, 2);
513                             }
514                     | INSTR_M3x2 omods dreg ',' sregs
515                             {
516                                 TRACE("M3x2\n");
517                                 asm_ctx.funcs->instr(&asm_ctx, BWRITERSIO_M3x2, $2.mod, $2.shift, 0, &$3, &$5, 2);
518                             }
519                     | INSTR_DCL dclusage REG_OUTPUT
520                             {
521                                 struct shader_reg reg;
522                                 TRACE("Output reg declaration\n");
523                                 ZeroMemory(&reg, sizeof(reg));
524                                 reg.type = BWRITERSPR_OUTPUT;
525                                 reg.regnum = $3;
526                                 reg.rel_reg = NULL;
527                                 reg.srcmod = 0;
528                                 reg.writemask = BWRITERSP_WRITEMASK_ALL;
529                                 asm_ctx.funcs->dcl_output(&asm_ctx, $2.dclusage, $2.regnum, &reg);
530                             }
531                     | INSTR_DCL dclusage REG_OUTPUT writemask
532                             {
533                                 struct shader_reg reg;
534                                 TRACE("Output reg declaration\n");
535                                 ZeroMemory(&reg, sizeof(reg));
536                                 reg.type = BWRITERSPR_OUTPUT;
537                                 reg.regnum = $3;
538                                 reg.rel_reg = NULL;
539                                 reg.srcmod = 0;
540                                 reg.writemask = $4;
541                                 asm_ctx.funcs->dcl_output(&asm_ctx, $2.dclusage, $2.regnum, &reg);
542                             }
543                     | INSTR_DCL dclusage omods dcl_inputreg
544                             {
545                                 struct shader_reg reg;
546                                 TRACE("Input reg declaration\n");
547                                 if($3.shift != 0) {
548                                     asmparser_message(&asm_ctx, "Line %u: Shift modifier not allowed here\n",
549                                                       asm_ctx.line_no);
550                                     set_parse_status(&asm_ctx, PARSE_ERR);
551                                 }
552                                 ZeroMemory(&reg, sizeof(reg));
553                                 reg.type = $4.type;
554                                 reg.regnum = $4.regnum;
555                                 reg.rel_reg = NULL;
556                                 reg.srcmod = 0;
557                                 reg.writemask = BWRITERSP_WRITEMASK_ALL;
558                                 asm_ctx.funcs->dcl_input(&asm_ctx, $2.dclusage, $2.regnum, $3.mod, &reg);
559                             }
560                     | INSTR_DCL dclusage omods dcl_inputreg writemask
561                             {
562                                 struct shader_reg reg;
563                                 TRACE("Input reg declaration\n");
564                                 if($3.shift != 0) {
565                                     asmparser_message(&asm_ctx, "Line %u: Shift modifier not allowed here\n",
566                                                       asm_ctx.line_no);
567                                     set_parse_status(&asm_ctx, PARSE_ERR);
568                                 }
569                                 ZeroMemory(&reg, sizeof(reg));
570                                 reg.type = $4.type;
571                                 reg.regnum = $4.regnum;
572                                 reg.rel_reg = NULL;
573                                 reg.srcmod = 0;
574                                 reg.writemask = $5;
575                                 asm_ctx.funcs->dcl_input(&asm_ctx, $2.dclusage, $2.regnum, $3.mod, &reg);
576                             }
577                     | INSTR_DCL omods dcl_inputreg
578                             {
579                                 struct shader_reg reg;
580                                 TRACE("Input reg declaration\n");
581                                 if($2.shift != 0) {
582                                     asmparser_message(&asm_ctx, "Line %u: Shift modifier not allowed here\n",
583                                                       asm_ctx.line_no);
584                                     set_parse_status(&asm_ctx, PARSE_ERR);
585                                 }
586                                 ZeroMemory(&reg, sizeof(reg));
587                                 reg.type = $3.type;
588                                 reg.regnum = $3.regnum;
589                                 reg.rel_reg = NULL;
590                                 reg.srcmod = 0;
591                                 reg.writemask = BWRITERSP_WRITEMASK_ALL;
592                                 asm_ctx.funcs->dcl_input(&asm_ctx, 0, 0, $2.mod, &reg);
593                             }
594                     | INSTR_DCL omods dcl_inputreg writemask
595                             {
596                                 struct shader_reg reg;
597                                 TRACE("Input reg declaration\n");
598                                 if($2.shift != 0) {
599                                     asmparser_message(&asm_ctx, "Line %u: Shift modifier not allowed here\n",
600                                                       asm_ctx.line_no);
601                                     set_parse_status(&asm_ctx, PARSE_ERR);
602                                 }
603                                 ZeroMemory(&reg, sizeof(reg));
604                                 reg.type = $3.type;
605                                 reg.regnum = $3.regnum;
606                                 reg.rel_reg = NULL;
607                                 reg.srcmod = 0;
608                                 reg.writemask = $4;
609                                 asm_ctx.funcs->dcl_input(&asm_ctx, 0, 0, $2.mod, &reg);
610                             }
611                     | INSTR_DCL sampdcl omods REG_SAMPLER
612                             {
613                                 TRACE("Sampler declared\n");
614                                 if($3.shift != 0) {
615                                     asmparser_message(&asm_ctx, "Line %u: Shift modifier not allowed here\n",
616                                                       asm_ctx.line_no);
617                                     set_parse_status(&asm_ctx, PARSE_ERR);
618                                 }
619                                 asm_ctx.funcs->dcl_sampler(&asm_ctx, $2, $3.mod, $4, asm_ctx.line_no);
620                             }
621                     | INSTR_DCL omods REG_SAMPLER
622                             {
623                                 TRACE("Sampler declared\n");
624                                 if($2.shift != 0) {
625                                     asmparser_message(&asm_ctx, "Line %u: Shift modifier not allowed here\n",
626                                                       asm_ctx.line_no);
627                                     set_parse_status(&asm_ctx, PARSE_ERR);
628                                 }
629                                 if(asm_ctx.shader->type != ST_PIXEL) {
630                                     asmparser_message(&asm_ctx, "Line %u: Declaration needs a sampler type\n",
631                                                       asm_ctx.line_no);
632                                     set_parse_status(&asm_ctx, PARSE_ERR);
633                                 }
634                                 asm_ctx.funcs->dcl_sampler(&asm_ctx, BWRITERSTT_UNKNOWN, $2.mod, $3, asm_ctx.line_no);
635                             }
636                     | INSTR_DCL sampdcl omods dcl_inputreg
637                             {
638                                 TRACE("Error rule: sampler decl of input reg\n");
639                                 asmparser_message(&asm_ctx, "Line %u: Sampler declarations of input regs is not valid\n",
640                                                   asm_ctx.line_no);
641                                 set_parse_status(&asm_ctx, PARSE_WARN);
642                             }
643                     | INSTR_DCL sampdcl omods REG_OUTPUT
644                             {
645                                 TRACE("Error rule: sampler decl of output reg\n");
646                                 asmparser_message(&asm_ctx, "Line %u: Sampler declarations of output regs is not valid\n",
647                                                   asm_ctx.line_no);
648                                 set_parse_status(&asm_ctx, PARSE_WARN);
649                             }
650                     | INSTR_DEF REG_CONSTFLOAT ',' IMMVAL ',' IMMVAL ',' IMMVAL ',' IMMVAL
651                             {
652                                 asm_ctx.funcs->constF(&asm_ctx, $2, $4.val, $6.val, $8.val, $10.val);
653                             }
654                     | INSTR_DEFI REG_CONSTINT ',' IMMVAL ',' IMMVAL ',' IMMVAL ',' IMMVAL
655                             {
656                                 asm_ctx.funcs->constI(&asm_ctx, $2, $4.val, $6.val, $8.val, $10.val);
657                             }
658                     | INSTR_DEFB REG_CONSTBOOL ',' IMMBOOL
659                             {
660                                 asm_ctx.funcs->constB(&asm_ctx, $2, $4);
661                             }
662                     | INSTR_REP sregs
663                             {
664                                 TRACE("REP\n");
665                                 asm_ctx.funcs->instr(&asm_ctx, BWRITERSIO_REP, 0, 0, 0, 0, &$2, 1);
666                             }
667                     | INSTR_ENDREP
668                             {
669                                 TRACE("ENDREP\n");
670                                 asm_ctx.funcs->instr(&asm_ctx, BWRITERSIO_ENDREP, 0, 0, 0, 0, 0, 0);
671                             }
672                     | INSTR_IF sregs
673                             {
674                                 TRACE("IF\n");
675                                 asm_ctx.funcs->instr(&asm_ctx, BWRITERSIO_IF, 0, 0, 0, 0, &$2, 1);
676                             }
677                     | INSTR_IF comp sregs
678                             {
679                                 TRACE("IFC\n");
680                                 asm_ctx.funcs->instr(&asm_ctx, BWRITERSIO_IFC, 0, 0, $2, 0, &$3, 2);
681                             }
682                     | INSTR_ELSE
683                             {
684                                 TRACE("ELSE\n");
685                                 asm_ctx.funcs->instr(&asm_ctx, BWRITERSIO_ELSE, 0, 0, 0, 0, 0, 0);
686                             }
687                     | INSTR_ENDIF
688                             {
689                                 TRACE("ENDIF\n");
690                                 asm_ctx.funcs->instr(&asm_ctx, BWRITERSIO_ENDIF, 0, 0, 0, 0, 0, 0);
691                             }
692                     | INSTR_BREAK
693                             {
694                                 TRACE("BREAK\n");
695                                 asm_ctx.funcs->instr(&asm_ctx, BWRITERSIO_BREAK, 0, 0, 0, 0, 0, 0);
696                             }
697                     | INSTR_BREAK comp sregs
698                             {
699                                 TRACE("BREAKC\n");
700                                 asm_ctx.funcs->instr(&asm_ctx, BWRITERSIO_BREAKC, 0, 0, $2, 0, &$3, 2);
701                             }
702                     | INSTR_BREAKP sregs
703                             {
704                                 TRACE("BREAKP\n");
705                                 asm_ctx.funcs->instr(&asm_ctx, BWRITERSIO_BREAKP, 0, 0, 0, 0, &$2, 1);
706                             }
707                     | INSTR_CALL sregs
708                             {
709                                 TRACE("CALL\n");
710                                 asm_ctx.funcs->instr(&asm_ctx, BWRITERSIO_CALL, 0, 0, 0, 0, &$2, 1);
711                             }
712                     | INSTR_CALLNZ sregs
713                             {
714                                 TRACE("CALLNZ\n");
715                                 asm_ctx.funcs->instr(&asm_ctx, BWRITERSIO_CALLNZ, 0, 0, 0, 0, &$2, 2);
716                             }
717                     | INSTR_LOOP sregs
718                             {
719                                 TRACE("LOOP\n");
720                                 asm_ctx.funcs->instr(&asm_ctx, BWRITERSIO_LOOP, 0, 0, 0, 0, &$2, 2);
721                             }
722                     | INSTR_RET
723                             {
724                                 TRACE("RET\n");
725                                 asm_ctx.funcs->instr(&asm_ctx, BWRITERSIO_RET, 0, 0, 0, 0, 0, 0);
726                             }
727                     | INSTR_ENDLOOP
728                             {
729                                 TRACE("ENDLOOP\n");
730                                 asm_ctx.funcs->instr(&asm_ctx, BWRITERSIO_ENDLOOP, 0, 0, 0, 0, 0, 0);
731                             }
732                     | INSTR_LABEL sregs
733                             {
734                                 TRACE("LABEL\n");
735                                 asm_ctx.funcs->instr(&asm_ctx, BWRITERSIO_LABEL, 0, 0, 0, 0, &$2, 1);
736                             }
737                     | INSTR_SETP comp dreg ',' sregs
738                             {
739                                 TRACE("SETP\n");
740                                 asm_ctx.funcs->instr(&asm_ctx, BWRITERSIO_SETP, 0, 0, $2, &$3, &$5, 2);
741                             }
742                     | INSTR_TEXLDL omods dreg ',' sregs
743                             {
744                                 TRACE("TEXLDL\n");
745                                 asm_ctx.funcs->instr(&asm_ctx, BWRITERSIO_TEXLDL, $2.mod, $2.shift, 0, &$3, &$5, 2);
746                             }
747                     | INSTR_LIT omods dreg ',' sregs
748                             {
749                                 TRACE("LIT\n");
750                                 asm_ctx.funcs->instr(&asm_ctx, BWRITERSIO_LIT, $2.mod, $2.shift, 0, &$3, &$5, 1);
751                             }
752                     | INSTR_MOVA omods dreg ',' sregs
753                             {
754                                 TRACE("MOVA\n");
755                                 asm_ctx.funcs->instr(&asm_ctx, BWRITERSIO_MOVA, $2.mod, $2.shift, 0, &$3, &$5, 1);
756                             }
757                     | INSTR_CMP omods dreg ',' sregs
758                             {
759                                 TRACE("CMP\n");
760                                 asm_ctx.funcs->instr(&asm_ctx, BWRITERSIO_CMP, $2.mod, $2.shift, 0, &$3, &$5, 3);
761                             }
762                     | INSTR_DP2ADD omods dreg ',' sregs
763                             {
764                                 TRACE("DP2ADD\n");
765                                 asm_ctx.funcs->instr(&asm_ctx, BWRITERSIO_DP2ADD, $2.mod, $2.shift, 0, &$3, &$5, 3);
766                             }
767                     | INSTR_TEXKILL dreg
768                             {
769                                 TRACE("TEXKILL\n");
770                                 asm_ctx.funcs->instr(&asm_ctx, BWRITERSIO_TEXKILL, 0, 0, 0, &$2, 0, 0);
771                             }
772                     | INSTR_TEXLD omods dreg ',' sregs
773                             {
774                                 TRACE("TEXLD\n");
775                                 /* There is more than one acceptable syntax for texld:
776                                    with 1 sreg (PS 1.4) or
777                                    with 2 sregs (PS 2.0+)
778                                    Moreover, texld shares the same opcode as the tex instruction,
779                                    so there are a total of 3 valid syntaxes
780                                    These variations are handled in asmparser.c */
781                                 asm_ctx.funcs->instr(&asm_ctx, BWRITERSIO_TEX, $2.mod, $2.shift, 0, &$3, &$5, 2);
782                             }
783                     | INSTR_TEXLDP omods dreg ',' sregs
784                             {
785                                 TRACE("TEXLDP\n");
786                                 asm_ctx.funcs->instr(&asm_ctx, BWRITERSIO_TEXLDP, $2.mod, $2.shift, 0, &$3, &$5, 2);
787                             }
788                     | INSTR_TEXLDB omods dreg ',' sregs
789                             {
790                                 TRACE("TEXLDB\n");
791                                 asm_ctx.funcs->instr(&asm_ctx, BWRITERSIO_TEXLDB, $2.mod, $2.shift, 0, &$3, &$5, 2);
792                             }
793                     | INSTR_DSX omods dreg ',' sregs
794                             {
795                                 TRACE("DSX\n");
796                                 asm_ctx.funcs->instr(&asm_ctx, BWRITERSIO_DSX, $2.mod, $2.shift, 0, &$3, &$5, 1);
797                             }
798                     | INSTR_DSY omods dreg ',' sregs
799                             {
800                                 TRACE("DSY\n");
801                                 asm_ctx.funcs->instr(&asm_ctx, BWRITERSIO_DSY, $2.mod, $2.shift, 0, &$3, &$5, 1);
802                             }
803                     | INSTR_TEXLDD omods dreg ',' sregs
804                             {
805                                 TRACE("TEXLDD\n");
806                                 asm_ctx.funcs->instr(&asm_ctx, BWRITERSIO_TEXLDD, $2.mod, $2.shift, 0, &$3, &$5, 4);
807                             }
808
809 dreg:                 dreg_name rel_reg
810                             {
811                                 $$.regnum = $1.regnum;
812                                 $$.type = $1.type;
813                                 $$.writemask = BWRITERSP_WRITEMASK_ALL;
814                                 $$.srcmod = BWRITERSPSM_NONE;
815                                 set_rel_reg(&$$, &$2);
816                             }
817                     | dreg_name writemask
818                             {
819                                 $$.regnum = $1.regnum;
820                                 $$.type = $1.type;
821                                 $$.writemask = $2;
822                                 $$.srcmod = BWRITERSPSM_NONE;
823                                 $$.rel_reg = NULL;
824                             }
825
826 dreg_name:            REG_TEMP
827                         {
828                             $$.regnum = $1; $$.type = BWRITERSPR_TEMP;
829                         }
830                     | REG_OUTPUT
831                         {
832                             $$.regnum = $1; $$.type = BWRITERSPR_OUTPUT;
833                         }
834                     | REG_INPUT
835                         {
836                             $$.regnum = $1; $$.type = BWRITERSPR_INPUT;
837                         }
838                     | REG_CONSTFLOAT
839                         {
840                             asmparser_message(&asm_ctx, "Line %u: Register c%u is not a valid destination register\n",
841                                               asm_ctx.line_no, $1);
842                             set_parse_status(&asm_ctx, PARSE_WARN);
843                         }
844                     | REG_CONSTINT
845                         {
846                           asmparser_message(&asm_ctx, "Line %u: Register i%u is not a valid destination register\n",
847                                               asm_ctx.line_no, $1);
848                             set_parse_status(&asm_ctx, PARSE_WARN);
849                         }
850                     | REG_CONSTBOOL
851                         {
852                             asmparser_message(&asm_ctx, "Line %u: Register b%u is not a valid destination register\n",
853                                               asm_ctx.line_no, $1);
854                             set_parse_status(&asm_ctx, PARSE_WARN);
855                         }
856                     | REG_TEXTURE
857                         {
858                             $$.regnum = $1; $$.type = BWRITERSPR_TEXTURE;
859                         }
860                     | REG_TEXCRDOUT
861                         {
862                             $$.regnum = $1; $$.type = BWRITERSPR_TEXCRDOUT;
863                         }
864                     | REG_SAMPLER
865                         {
866                             asmparser_message(&asm_ctx, "Line %u: Register s%u is not a valid destination register\n",
867                                               asm_ctx.line_no, $1);
868                             set_parse_status(&asm_ctx, PARSE_WARN);
869                         }
870                     | REG_OPOS
871                         {
872                             $$.regnum = BWRITERSRO_POSITION; $$.type = BWRITERSPR_RASTOUT;
873                         }
874                     | REG_OPTS
875                         {
876                             $$.regnum = BWRITERSRO_POINT_SIZE; $$.type = BWRITERSPR_RASTOUT;
877                         }
878                     | REG_OFOG
879                         {
880                             $$.regnum = BWRITERSRO_FOG; $$.type = BWRITERSPR_RASTOUT;
881                         }
882                     | REG_VERTEXCOLOR
883                         {
884                             $$.regnum = $1; $$.type = BWRITERSPR_ATTROUT;
885                         }
886                     | REG_FRAGCOLOR
887                         {
888                             $$.regnum = $1; $$.type = BWRITERSPR_COLOROUT;
889                         }
890                     | REG_FRAGDEPTH
891                         {
892                             $$.regnum = 0; $$.type = BWRITERSPR_DEPTHOUT;
893                         }
894                     | REG_PREDICATE
895                         {
896                             $$.regnum = 0; $$.type = BWRITERSPR_PREDICATE;
897                         }
898                     | REG_VPOS
899                         {
900                             asmparser_message(&asm_ctx, "Line %u: Register vPos is not a valid destination register\n",
901                                               asm_ctx.line_no);
902                             set_parse_status(&asm_ctx, PARSE_WARN);
903                         }
904                     | REG_VFACE
905                         {
906                             asmparser_message(&asm_ctx, "Line %u: Register vFace is not a valid destination register\n",
907                                               asm_ctx.line_no);
908                             set_parse_status(&asm_ctx, PARSE_WARN);
909                         }
910                     | REG_ADDRESS
911                         {
912                             /* index 0 is hardcoded for the addr register */
913                             $$.regnum = 0; $$.type = BWRITERSPR_ADDR;
914                         }
915                     | REG_LOOP
916                         {
917                             asmparser_message(&asm_ctx, "Line %u: Register aL is not a valid destination register\n",
918                                               asm_ctx.line_no);
919                             set_parse_status(&asm_ctx, PARSE_WARN);
920                         }
921
922 writemask:            '.' wm_components
923                         {
924                             if($2.writemask == SWIZZLE_ERR) {
925                                 asmparser_message(&asm_ctx, "Line %u: Invalid writemask specified\n",
926                                                   asm_ctx.line_no);
927                                 set_parse_status(&asm_ctx, PARSE_ERR);
928                                 /* Provide a correct writemask to prevent following complaints */
929                                 $$ = BWRITERSP_WRITEMASK_ALL;
930                             }
931                             else {
932                                 $$ = $2.writemask;
933                                 TRACE("Writemask: %x\n", $$);
934                             }
935                         }
936
937 wm_components:        COMPONENT
938                         {
939                             $$.writemask = 1 << $1;
940                             $$.last = $1;
941                             $$.idx = 1;
942                         }
943                     | wm_components COMPONENT
944                         {
945                             if($1.writemask == SWIZZLE_ERR || $1.idx == 4)
946                                 /* Wrong writemask */
947                                 $$.writemask = SWIZZLE_ERR;
948                             else {
949                                 if($2 <= $1.last)
950                                     $$.writemask = SWIZZLE_ERR;
951                                 else {
952                                     $$.writemask = $1.writemask | (1 << $2);
953                                     $$.idx = $1.idx + 1;
954                                 }
955                             }
956                         }
957
958 swizzle:              /* empty */
959                         {
960                             $$ = BWRITERVS_NOSWIZZLE;
961                             TRACE("Default swizzle: %08x\n", $$);
962                         }
963                     | '.' sw_components
964                         {
965                             if($2.swizzle == SWIZZLE_ERR) {
966                                 asmparser_message(&asm_ctx, "Line %u: Invalid swizzle\n",
967                                                   asm_ctx.line_no);
968                                 set_parse_status(&asm_ctx, PARSE_ERR);
969                                 /* Provide a correct swizzle to prevent following complaints */
970                                 $$ = BWRITERVS_NOSWIZZLE;
971                             }
972                             else {
973                                 DWORD last, i;
974
975                                 $$ = $2.swizzle << BWRITERVS_SWIZZLE_SHIFT;
976                                 /* Fill the swizzle by extending the last component */
977                                 last = ($2.swizzle >> 2 * ($2.idx - 1)) & 0x03;
978                                 for(i = $2.idx; i < 4; i++){
979                                     $$ |= last << (BWRITERVS_SWIZZLE_SHIFT + 2 * i);
980                                 }
981                                 TRACE("Got a swizzle: %08x\n", $$);
982                             }
983                         }
984
985 sw_components:        COMPONENT
986                         {
987                             $$.swizzle = $1;
988                             $$.idx = 1;
989                         }
990                     | sw_components COMPONENT
991                         {
992                             if($1.idx == 4) {
993                                 /* Too many sw_components */
994                                 $$.swizzle = SWIZZLE_ERR;
995                                 $$.idx = 4;
996                             }
997                             else {
998                                 $$.swizzle = $1.swizzle | ($2 << 2 * $1.idx);
999                                 $$.idx = $1.idx + 1;
1000                             }
1001                         }
1002
1003 omods:                 /* Empty */
1004                         {
1005                             $$.mod = 0;
1006                             $$.shift = 0;
1007                         }
1008                     | omods omodifier
1009                         {
1010                             $$.mod = $1.mod | $2.mod;
1011                             if($1.shift && $2.shift) {
1012                                 asmparser_message(&asm_ctx, "Line %u: More than one shift flag\n",
1013                                                   asm_ctx.line_no);
1014                                 set_parse_status(&asm_ctx, PARSE_ERR);
1015                                 $$.shift = $1.shift;
1016                             } else {
1017                                 $$.shift = $1.shift | $2.shift;
1018                             }
1019                         }
1020
1021 omodifier:            MOD_SAT
1022                         {
1023                             $$.mod = BWRITERSPDM_SATURATE;
1024                             $$.shift = 0;
1025                         }
1026                     | MOD_PP
1027                         {
1028                             $$.mod = BWRITERSPDM_PARTIALPRECISION;
1029                             $$.shift = 0;
1030                         }
1031                     | MOD_CENTROID
1032                         {
1033                             $$.mod = BWRITERSPDM_MSAMPCENTROID;
1034                             $$.shift = 0;
1035                         }
1036
1037 sregs:                sreg
1038                         {
1039                             $$.reg[0] = $1;
1040                             $$.count = 1;
1041                         }
1042                     | sregs ',' sreg
1043                         {
1044                             if($$.count == MAX_SRC_REGS){
1045                                 asmparser_message(&asm_ctx, "Line %u: Too many source registers in this instruction\n",
1046                                                   asm_ctx.line_no);
1047                                 set_parse_status(&asm_ctx, PARSE_ERR);
1048                             }
1049                             else
1050                                 $$.reg[$$.count++] = $3;
1051                         }
1052
1053 sreg:                   sreg_name rel_reg swizzle
1054                         {
1055                             $$.type = $1.type;
1056                             $$.regnum = $1.regnum;
1057                             $$.swizzle = $3;
1058                             $$.srcmod = BWRITERSPSM_NONE;
1059                             set_rel_reg(&$$, &$2);
1060                         }
1061                     | sreg_name rel_reg smod swizzle
1062                         {
1063                             $$.type = $1.type;
1064                             $$.regnum = $1.regnum;
1065                             set_rel_reg(&$$, &$2);
1066                             $$.srcmod = $3;
1067                             $$.swizzle = $4;
1068                         }
1069                     | '-' sreg_name rel_reg swizzle
1070                         {
1071                             $$.type = $2.type;
1072                             $$.regnum = $2.regnum;
1073                             $$.srcmod = BWRITERSPSM_NEG;
1074                             set_rel_reg(&$$, &$3);
1075                             $$.swizzle = $4;
1076                         }
1077                     | '-' sreg_name rel_reg smod swizzle
1078                         {
1079                             $$.type = $2.type;
1080                             $$.regnum = $2.regnum;
1081                             set_rel_reg(&$$, &$3);
1082                             switch($4) {
1083                                 case BWRITERSPSM_ABS:  $$.srcmod = BWRITERSPSM_ABSNEG;  break;
1084                                 default:
1085                                     FIXME("Unhandled combination of NEGATE and %u\n", $4);
1086                             }
1087                             $$.swizzle = $5;
1088                         }
1089                     | SMOD_NOT sreg_name swizzle
1090                         {
1091                             $$.type = $2.type;
1092                             $$.regnum = $2.regnum;
1093                             $$.rel_reg = NULL;
1094                             $$.srcmod = BWRITERSPSM_NOT;
1095                             $$.swizzle = $3;
1096                         }
1097
1098 rel_reg:               /* empty */
1099                         {
1100                             $$.has_rel_reg = FALSE;
1101                             $$.additional_offset = 0;
1102                         }
1103                     | '[' immsum ']'
1104                         {
1105                             $$.has_rel_reg = FALSE;
1106                             $$.additional_offset = $2.val;
1107                         }
1108                     | '[' relreg_name swizzle ']'
1109                         {
1110                             $$.has_rel_reg = TRUE;
1111                             $$.type = $2.type;
1112                             $$.additional_offset = 0;
1113                             $$.rel_regnum = $2.regnum;
1114                             $$.swizzle = $3;
1115                         }
1116                     | '[' immsum '+' relreg_name swizzle ']'
1117                         {
1118                             $$.has_rel_reg = TRUE;
1119                             $$.type = $4.type;
1120                             $$.additional_offset = $2.val;
1121                             $$.rel_regnum = $4.regnum;
1122                             $$.swizzle = $5;
1123                         }
1124                     | '[' relreg_name swizzle '+' immsum ']'
1125                         {
1126                             $$.has_rel_reg = TRUE;
1127                             $$.type = $2.type;
1128                             $$.additional_offset = $5.val;
1129                             $$.rel_regnum = $2.regnum;
1130                             $$.swizzle = $3;
1131                         }
1132                     | '[' immsum '+' relreg_name swizzle '+' immsum ']'
1133                         {
1134                             $$.has_rel_reg = TRUE;
1135                             $$.type = $4.type;
1136                             $$.additional_offset = $2.val + $7.val;
1137                             $$.rel_regnum = $4.regnum;
1138                             $$.swizzle = $5;
1139                         }
1140
1141 immsum:               IMMVAL
1142                         {
1143                             if(!$1.integer) {
1144                                 asmparser_message(&asm_ctx, "Line %u: Unexpected float %f\n",
1145                                                   asm_ctx.line_no, $1.val);
1146                                 set_parse_status(&asm_ctx, PARSE_ERR);
1147                             }
1148                             $$.val = $1.val;
1149                         }
1150                     | immsum '+' IMMVAL
1151                         {
1152                             if(!$3.integer) {
1153                                 asmparser_message(&asm_ctx, "Line %u: Unexpected float %f\n",
1154                                                   asm_ctx.line_no, $3.val);
1155                                 set_parse_status(&asm_ctx, PARSE_ERR);
1156                             }
1157                             $$.val = $1.val + $3.val;
1158                         }
1159
1160 smod:                 SMOD_ABS
1161                         {
1162                             $$ = BWRITERSPSM_ABS;
1163                         }
1164
1165 relreg_name:          REG_ADDRESS
1166                         {
1167                             $$.regnum = 0; $$.type = BWRITERSPR_ADDR;
1168                         }
1169                     | REG_LOOP
1170                         {
1171                             $$.regnum = 0; $$.type = BWRITERSPR_LOOP;
1172                         }
1173
1174 sreg_name:            REG_TEMP
1175                         {
1176                             $$.regnum = $1; $$.type = BWRITERSPR_TEMP;
1177                         }
1178                     | REG_OUTPUT
1179                         {
1180                             asmparser_message(&asm_ctx, "Line %u: Register o%u is not a valid source register\n",
1181                                               asm_ctx.line_no, $1);
1182                             set_parse_status(&asm_ctx, PARSE_WARN);
1183                         }
1184                     | REG_INPUT
1185                         {
1186                             $$.regnum = $1; $$.type = BWRITERSPR_INPUT;
1187                         }
1188                     | REG_CONSTFLOAT
1189                         {
1190                             $$.regnum = $1; $$.type = BWRITERSPR_CONST;
1191                         }
1192                     | REG_CONSTINT
1193                         {
1194                             $$.regnum = $1; $$.type = BWRITERSPR_CONSTINT;
1195                         }
1196                     | REG_CONSTBOOL
1197                         {
1198                             $$.regnum = $1; $$.type = BWRITERSPR_CONSTBOOL;
1199                         }
1200                     | REG_TEXTURE
1201                         {
1202                             $$.regnum = $1; $$.type = BWRITERSPR_TEXTURE;
1203                         }
1204                     | REG_TEXCRDOUT
1205                         {
1206                             asmparser_message(&asm_ctx, "Line %u: Register oT%u is not a valid source register\n",
1207                                               asm_ctx.line_no, $1);
1208                             set_parse_status(&asm_ctx, PARSE_WARN);
1209                         }
1210                     | REG_SAMPLER
1211                         {
1212                             $$.regnum = $1; $$.type = BWRITERSPR_SAMPLER;
1213                         }
1214                     | REG_OPOS
1215                         {
1216                             asmparser_message(&asm_ctx, "Line %u: Register oPos is not a valid source register\n",
1217                                               asm_ctx.line_no);
1218                             set_parse_status(&asm_ctx, PARSE_WARN);
1219                         }
1220                     | REG_OFOG
1221                         {
1222                             asmparser_message(&asm_ctx, "Line %u: Register oFog is not a valid source register\n",
1223                                               asm_ctx.line_no);
1224                             set_parse_status(&asm_ctx, PARSE_WARN);
1225                         }
1226                     | REG_VERTEXCOLOR
1227                         {
1228                             asmparser_message(&asm_ctx, "Line %u: Register oD%u is not a valid source register\n",
1229                                               asm_ctx.line_no, $1);
1230                             set_parse_status(&asm_ctx, PARSE_WARN);
1231                         }
1232                     | REG_FRAGCOLOR
1233                         {
1234                             asmparser_message(&asm_ctx, "Line %u: Register oC%u is not a valid source register\n",
1235                                               asm_ctx.line_no, $1);
1236                             set_parse_status(&asm_ctx, PARSE_WARN);
1237                         }
1238                     | REG_FRAGDEPTH
1239                         {
1240                             asmparser_message(&asm_ctx, "Line %u: Register oDepth is not a valid source register\n",
1241                                               asm_ctx.line_no);
1242                             set_parse_status(&asm_ctx, PARSE_WARN);
1243                         }
1244                     | REG_PREDICATE
1245                         {
1246                             $$.regnum = 0; $$.type = BWRITERSPR_PREDICATE;
1247                         }
1248                     | REG_VPOS
1249                         {
1250                             $$.regnum = 0; $$.type = BWRITERSPR_MISCTYPE;
1251                         }
1252                     | REG_VFACE
1253                         {
1254                             $$.regnum = 1; $$.type = BWRITERSPR_MISCTYPE;
1255                         }
1256                     | REG_ADDRESS
1257                         {
1258                             $$.regnum = 0; $$.type = BWRITERSPR_ADDR;
1259                         }
1260                     | REG_LOOP
1261                         {
1262                             $$.regnum = 0; $$.type = BWRITERSPR_LOOP;
1263                         }
1264                     | REG_LABEL
1265                         {
1266                             $$.regnum = $1; $$.type = BWRITERSPR_LABEL;
1267                         }
1268
1269 comp:                 COMP_GT           { $$ = BWRITER_COMPARISON_GT;       }
1270                     | COMP_LT           { $$ = BWRITER_COMPARISON_LT;       }
1271                     | COMP_GE           { $$ = BWRITER_COMPARISON_GE;       }
1272                     | COMP_LE           { $$ = BWRITER_COMPARISON_LE;       }
1273                     | COMP_EQ           { $$ = BWRITER_COMPARISON_EQ;       }
1274                     | COMP_NE           { $$ = BWRITER_COMPARISON_NE;       }
1275
1276 dclusage:             USAGE_POSITION
1277                         {
1278                             TRACE("dcl_position%u\n", $1);
1279                             $$.regnum = $1;
1280                             $$.dclusage = BWRITERDECLUSAGE_POSITION;
1281                         }
1282                     | USAGE_BLENDWEIGHT
1283                         {
1284                             TRACE("dcl_blendweight%u\n", $1);
1285                             $$.regnum = $1;
1286                             $$.dclusage = BWRITERDECLUSAGE_BLENDWEIGHT;
1287                         }
1288                     | USAGE_BLENDINDICES
1289                         {
1290                             TRACE("dcl_blendindices%u\n", $1);
1291                             $$.regnum = $1;
1292                             $$.dclusage = BWRITERDECLUSAGE_BLENDINDICES;
1293                         }
1294                     | USAGE_NORMAL
1295                         {
1296                             TRACE("dcl_normal%u\n", $1);
1297                             $$.regnum = $1;
1298                             $$.dclusage = BWRITERDECLUSAGE_NORMAL;
1299                         }
1300                     | USAGE_PSIZE
1301                         {
1302                             TRACE("dcl_psize%u\n", $1);
1303                             $$.regnum = $1;
1304                             $$.dclusage = BWRITERDECLUSAGE_PSIZE;
1305                         }
1306                     | USAGE_TEXCOORD
1307                         {
1308                             TRACE("dcl_texcoord%u\n", $1);
1309                             $$.regnum = $1;
1310                             $$.dclusage = BWRITERDECLUSAGE_TEXCOORD;
1311                         }
1312                     | USAGE_TANGENT
1313                         {
1314                             TRACE("dcl_tangent%u\n", $1);
1315                             $$.regnum = $1;
1316                             $$.dclusage = BWRITERDECLUSAGE_TANGENT;
1317                         }
1318                     | USAGE_BINORMAL
1319                         {
1320                             TRACE("dcl_binormal%u\n", $1);
1321                             $$.regnum = $1;
1322                             $$.dclusage = BWRITERDECLUSAGE_BINORMAL;
1323                         }
1324                     | USAGE_TESSFACTOR
1325                         {
1326                             TRACE("dcl_tessfactor%u\n", $1);
1327                             $$.regnum = $1;
1328                             $$.dclusage = BWRITERDECLUSAGE_TESSFACTOR;
1329                         }
1330                     | USAGE_POSITIONT
1331                         {
1332                             TRACE("dcl_positiont%u\n", $1);
1333                             $$.regnum = $1;
1334                             $$.dclusage = BWRITERDECLUSAGE_POSITIONT;
1335                         }
1336                     | USAGE_COLOR
1337                         {
1338                             TRACE("dcl_color%u\n", $1);
1339                             $$.regnum = $1;
1340                             $$.dclusage = BWRITERDECLUSAGE_COLOR;
1341                         }
1342                     | USAGE_FOG
1343                         {
1344                             TRACE("dcl_fog%u\n", $1);
1345                             $$.regnum = $1;
1346                             $$.dclusage = BWRITERDECLUSAGE_FOG;
1347                         }
1348                     | USAGE_DEPTH
1349                         {
1350                             TRACE("dcl_depth%u\n", $1);
1351                             $$.regnum = $1;
1352                             $$.dclusage = BWRITERDECLUSAGE_DEPTH;
1353                         }
1354                     | USAGE_SAMPLE
1355                         {
1356                             TRACE("dcl_sample%u\n", $1);
1357                             $$.regnum = $1;
1358                             $$.dclusage = BWRITERDECLUSAGE_SAMPLE;
1359                         }
1360
1361 dcl_inputreg:         REG_INPUT
1362                         {
1363                             $$.regnum = $1; $$.type = BWRITERSPR_INPUT;
1364                         }
1365                     | REG_TEXTURE
1366                         {
1367                             $$.regnum = $1; $$.type = BWRITERSPR_TEXTURE;
1368                         }
1369
1370 sampdcl:              SAMPTYPE_1D
1371                         {
1372                             $$ = BWRITERSTT_1D;
1373                         }
1374                     | SAMPTYPE_2D
1375                         {
1376                             $$ = BWRITERSTT_2D;
1377                         }
1378                     | SAMPTYPE_CUBE
1379                         {
1380                             $$ = BWRITERSTT_CUBE;
1381                         }
1382                     | SAMPTYPE_VOLUME
1383                         {
1384                             $$ = BWRITERSTT_VOLUME;
1385                         }
1386
1387 predicate:            '(' REG_PREDICATE swizzle ')'
1388                         {
1389                             $$.type = BWRITERSPR_PREDICATE;
1390                             $$.regnum = 0;
1391                             $$.rel_reg = NULL;
1392                             $$.srcmod = BWRITERSPSM_NONE;
1393                             $$.swizzle = $3;
1394                         }
1395                     | '(' SMOD_NOT REG_PREDICATE swizzle ')'
1396                         {
1397                             $$.type = BWRITERSPR_PREDICATE;
1398                             $$.regnum = 0;
1399                             $$.rel_reg = NULL;
1400                             $$.srcmod = BWRITERSPSM_NOT;
1401                             $$.swizzle = $4;
1402                         }
1403
1404 %%
1405
1406 void asmshader_error (char const *s) {
1407     asmparser_message(&asm_ctx, "Line %u: Error \"%s\" from bison\n", asm_ctx.line_no, s);
1408     set_parse_status(&asm_ctx, PARSE_ERR);
1409 }
1410
1411 /* Error reporting function */
1412 void asmparser_message(struct asm_parser *ctx, const char *fmt, ...) {
1413     va_list args;
1414     char* newbuffer;
1415     int rc, newsize;
1416
1417     if(ctx->messagecapacity == 0) {
1418         ctx->messages = asm_alloc(MESSAGEBUFFER_INITIAL_SIZE);
1419         if(ctx->messages == NULL) {
1420             ERR("Error allocating memory for parser messages\n");
1421             return;
1422         }
1423         ctx->messagecapacity = MESSAGEBUFFER_INITIAL_SIZE;
1424     }
1425
1426     while(1) {
1427         va_start(args, fmt);
1428         rc = vsnprintf(ctx->messages + ctx->messagesize,
1429                        ctx->messagecapacity - ctx->messagesize, fmt, args);
1430         va_end(args);
1431
1432         if (rc < 0 ||                                           /* C89 */
1433             rc >= ctx->messagecapacity - ctx->messagesize) {    /* C99 */
1434             /* Resize the buffer */
1435             newsize = ctx->messagecapacity * 2;
1436             newbuffer = asm_realloc(ctx->messages, newsize);
1437             if(newbuffer == NULL){
1438                 ERR("Error reallocating memory for parser messages\n");
1439                 return;
1440             }
1441             ctx->messages = newbuffer;
1442             ctx->messagecapacity = newsize;
1443         } else {
1444             ctx->messagesize += rc;
1445             return;
1446         }
1447     }
1448 }
1449
1450 /* New status is the worst between current status and parameter value */
1451 void set_parse_status(struct asm_parser *ctx, enum parse_status status) {
1452     if(status == PARSE_ERR) ctx->status = PARSE_ERR;
1453     else if(status == PARSE_WARN && ctx->status == PARSE_SUCCESS) ctx->status = PARSE_WARN;
1454 }
1455
1456 struct bwriter_shader *parse_asm_shader(char **messages) {
1457     struct bwriter_shader *ret = NULL;
1458
1459     asm_ctx.shader = NULL;
1460     asm_ctx.status = PARSE_SUCCESS;
1461     asm_ctx.messagesize = asm_ctx.messagecapacity = 0;
1462     asm_ctx.line_no = 1;
1463
1464     asmshader_parse();
1465
1466     if(asm_ctx.status != PARSE_ERR) ret = asm_ctx.shader;
1467     else if(asm_ctx.shader) SlDeleteShader(asm_ctx.shader);
1468
1469     if(messages) {
1470         if(asm_ctx.messagesize) {
1471             /* Shrink the buffer to the used size */
1472             *messages = asm_realloc(asm_ctx.messages, asm_ctx.messagesize + 1);
1473             if(!*messages) {
1474                 ERR("Out of memory, no messages reported\n");
1475                 asm_free(asm_ctx.messages);
1476             }
1477         } else {
1478             *messages = NULL;
1479         }
1480     } else {
1481         if(asm_ctx.messagecapacity) asm_free(asm_ctx.messages);
1482     }
1483
1484     return ret;
1485 }