d3dx9: Add ps_3_0 instructions parsing to the shader assembler.
[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 <samplertype> sampdcl
259 %type <rel_reg> rel_reg
260 %type <reg> predicate
261 %type <immval> immsum
262 %type <sregs> sregs
263
264 %%
265
266 shader:               version_marker instructions
267                         {
268                             asm_ctx.funcs->end(&asm_ctx);
269                         }
270
271 version_marker:       VER_VS10
272                         {
273                             TRACE("Vertex shader 1.0\n");
274                             set_parse_status(&asm_ctx, PARSE_ERR);
275                             YYABORT;
276                         }
277                     | VER_VS11
278                         {
279                             TRACE("Vertex shader 1.1\n");
280                             set_parse_status(&asm_ctx, PARSE_ERR);
281                             YYABORT;
282                         }
283                     | VER_VS20
284                         {
285                             TRACE("Vertex shader 2.0\n");
286                             set_parse_status(&asm_ctx, PARSE_ERR);
287                             YYABORT;
288                         }
289                     | VER_VS2X
290                         {
291                             TRACE("Vertex shader 2.x\n");
292                             set_parse_status(&asm_ctx, PARSE_ERR);
293                             YYABORT;
294                         }
295                     | VER_VS30
296                         {
297                             TRACE("Vertex shader 3.0\n");
298                             create_vs30_parser(&asm_ctx);
299                         }
300                     | VER_PS10
301                         {
302                             TRACE("Pixel  shader 1.0\n");
303                             set_parse_status(&asm_ctx, PARSE_ERR);
304                             YYABORT;
305                         }
306                     | VER_PS11
307                         {
308                             TRACE("Pixel  shader 1.1\n");
309                             set_parse_status(&asm_ctx, PARSE_ERR);
310                             YYABORT;
311                         }
312                     | VER_PS12
313                         {
314                             TRACE("Pixel  shader 1.2\n");
315                             set_parse_status(&asm_ctx, PARSE_ERR);
316                             YYABORT;
317                         }
318                     | VER_PS13
319                         {
320                             TRACE("Pixel  shader 1.3\n");
321                             set_parse_status(&asm_ctx, PARSE_ERR);
322                             YYABORT;
323                         }
324                     | VER_PS14
325                         {
326                             TRACE("Pixel  shader 1.4\n");
327                             set_parse_status(&asm_ctx, PARSE_ERR);
328                             YYABORT;
329                         }
330                     | VER_PS20
331                         {
332                             TRACE("Pixel  shader 2.0\n");
333                             set_parse_status(&asm_ctx, PARSE_ERR);
334                             YYABORT;
335                         }
336                     | VER_PS2X
337                         {
338                             TRACE("Pixel  shader 2.x\n");
339                             set_parse_status(&asm_ctx, PARSE_ERR);
340                             YYABORT;
341                         }
342                     | VER_PS30
343                         {
344                             TRACE("Pixel  shader 3.0\n");
345                             set_parse_status(&asm_ctx, PARSE_ERR);
346                             YYABORT;
347                         }
348
349 instructions:         /* empty */
350                     | instructions complexinstr
351                             {
352                                 /* Nothing to do */
353                             }
354
355 complexinstr:         instruction
356                             {
357
358                             }
359                     | predicate instruction
360                             {
361                                 TRACE("predicate\n");
362                                 asm_ctx.funcs->predicate(&asm_ctx, &$1);
363                             }
364
365 instruction:          INSTR_ADD omods dreg ',' sregs
366                             {
367                                 TRACE("ADD\n");
368                                 asm_ctx.funcs->instr(&asm_ctx, BWRITERSIO_ADD, $2.mod, $2.shift, 0, &$3, &$5, 2);
369                             }
370                     | INSTR_NOP
371                             {
372                                 TRACE("NOP\n");
373                                 asm_ctx.funcs->instr(&asm_ctx, BWRITERSIO_NOP, 0, 0, 0, 0, 0, 0);
374                             }
375                     | INSTR_MOV omods dreg ',' sregs
376                             {
377                                 TRACE("MOV\n");
378                                 asm_ctx.funcs->instr(&asm_ctx, BWRITERSIO_MOV, $2.mod, $2.shift, 0, &$3, &$5, 1);
379                             }
380                     | INSTR_SUB omods dreg ',' sregs
381                             {
382                                 TRACE("SUB\n");
383                                 asm_ctx.funcs->instr(&asm_ctx, BWRITERSIO_SUB, $2.mod, $2.shift, 0, &$3, &$5, 2);
384                             }
385                     | INSTR_MAD omods dreg ',' sregs
386                             {
387                                 TRACE("MAD\n");
388                                 asm_ctx.funcs->instr(&asm_ctx, BWRITERSIO_MAD, $2.mod, $2.shift, 0, &$3, &$5, 3);
389                             }
390                     | INSTR_MUL omods dreg ',' sregs
391                             {
392                                 TRACE("MUL\n");
393                                 asm_ctx.funcs->instr(&asm_ctx, BWRITERSIO_MUL, $2.mod, $2.shift, 0, &$3, &$5, 2);
394                             }
395                     | INSTR_RCP omods dreg ',' sregs
396                             {
397                                 TRACE("RCP\n");
398                                 asm_ctx.funcs->instr(&asm_ctx, BWRITERSIO_RCP, $2.mod, $2.shift, 0, &$3, &$5, 1);
399                             }
400                     | INSTR_RSQ omods dreg ',' sregs
401                             {
402                                 TRACE("RSQ\n");
403                                 asm_ctx.funcs->instr(&asm_ctx, BWRITERSIO_RSQ, $2.mod, $2.shift, 0, &$3, &$5, 1);
404                             }
405                     | INSTR_DP3 omods dreg ',' sregs
406                             {
407                                 TRACE("DP3\n");
408                                 asm_ctx.funcs->instr(&asm_ctx, BWRITERSIO_DP3, $2.mod, $2.shift, 0, &$3, &$5, 2);
409                             }
410                     | INSTR_DP4 omods dreg ',' sregs
411                             {
412                                 TRACE("DP4\n");
413                                 asm_ctx.funcs->instr(&asm_ctx, BWRITERSIO_DP4, $2.mod, $2.shift, 0, &$3, &$5, 2);
414                             }
415                     | INSTR_MIN omods dreg ',' sregs
416                             {
417                                 TRACE("MIN\n");
418                                 asm_ctx.funcs->instr(&asm_ctx, BWRITERSIO_MIN, $2.mod, $2.shift, 0, &$3, &$5, 2);
419                             }
420                     | INSTR_MAX omods dreg ',' sregs
421                             {
422                                 TRACE("MAX\n");
423                                 asm_ctx.funcs->instr(&asm_ctx, BWRITERSIO_MAX, $2.mod, $2.shift, 0, &$3, &$5, 2);
424                             }
425                     | INSTR_SLT omods dreg ',' sregs
426                             {
427                                 TRACE("SLT\n");
428                                 asm_ctx.funcs->instr(&asm_ctx, BWRITERSIO_SLT, $2.mod, $2.shift, 0, &$3, &$5, 2);
429                             }
430                     | INSTR_SGE omods dreg ',' sregs
431                             {
432                                 TRACE("SGE\n");
433                                 asm_ctx.funcs->instr(&asm_ctx, BWRITERSIO_SGE, $2.mod, $2.shift, 0, &$3, &$5, 2);
434                             }
435                     | INSTR_ABS omods dreg ',' sregs
436                             {
437                                 TRACE("ABS\n");
438                                 asm_ctx.funcs->instr(&asm_ctx, BWRITERSIO_ABS, $2.mod, $2.shift, 0, &$3, &$5, 1);
439                             }
440                     | INSTR_EXP omods dreg ',' sregs
441                             {
442                                 TRACE("EXP\n");
443                                 asm_ctx.funcs->instr(&asm_ctx, BWRITERSIO_EXP, $2.mod, $2.shift, 0, &$3, &$5, 1);
444                             }
445                     | INSTR_LOG omods dreg ',' sregs
446                             {
447                                 TRACE("LOG\n");
448                                 asm_ctx.funcs->instr(&asm_ctx, BWRITERSIO_LOG, $2.mod, $2.shift, 0, &$3, &$5, 1);
449                             }
450                     | INSTR_LOGP omods dreg ',' sregs
451                             {
452                                 TRACE("LOGP\n");
453                                 asm_ctx.funcs->instr(&asm_ctx, BWRITERSIO_LOGP, $2.mod, $2.shift, 0, &$3, &$5, 1);
454                             }
455                     | INSTR_EXPP omods dreg ',' sregs
456                             {
457                                 TRACE("EXPP\n");
458                                 asm_ctx.funcs->instr(&asm_ctx, BWRITERSIO_EXPP, $2.mod, $2.shift, 0, &$3, &$5, 1);
459                             }
460                     | INSTR_DST omods dreg ',' sregs
461                             {
462                                 TRACE("DST\n");
463                                 asm_ctx.funcs->instr(&asm_ctx, BWRITERSIO_DST, $2.mod, $2.shift, 0, &$3, &$5, 2);
464                             }
465                     | INSTR_LRP omods dreg ',' sregs
466                             {
467                                 TRACE("LRP\n");
468                                 asm_ctx.funcs->instr(&asm_ctx, BWRITERSIO_LRP, $2.mod, $2.shift, 0, &$3, &$5, 3);
469                             }
470                     | INSTR_FRC omods dreg ',' sregs
471                             {
472                                 TRACE("FRC\n");
473                                 asm_ctx.funcs->instr(&asm_ctx, BWRITERSIO_FRC, $2.mod, $2.shift, 0, &$3, &$5, 1);
474                             }
475                     | INSTR_POW omods dreg ',' sregs
476                             {
477                                 TRACE("POW\n");
478                                 asm_ctx.funcs->instr(&asm_ctx, BWRITERSIO_POW, $2.mod, $2.shift, 0, &$3, &$5, 2);
479                             }
480                     | INSTR_CRS omods dreg ',' sregs
481                             {
482                                 TRACE("CRS\n");
483                                 asm_ctx.funcs->instr(&asm_ctx, BWRITERSIO_CRS, $2.mod, $2.shift, 0, &$3, &$5, 2);
484                             }
485                     | INSTR_SGN omods dreg ',' sregs
486                             {
487                                 TRACE("SGN\n");
488                                 asm_ctx.funcs->instr(&asm_ctx, BWRITERSIO_SGN, $2.mod, $2.shift, 0, &$3, &$5, 3);
489                             }
490                     | INSTR_NRM omods dreg ',' sregs
491                             {
492                                 TRACE("NRM\n");
493                                 asm_ctx.funcs->instr(&asm_ctx, BWRITERSIO_NRM, $2.mod, $2.shift, 0, &$3, &$5, 1);
494                             }
495                     | INSTR_SINCOS omods dreg ',' sregs
496                             {
497                                 TRACE("SINCOS\n");
498                                 asm_ctx.funcs->instr(&asm_ctx, BWRITERSIO_SINCOS, $2.mod, $2.shift, 0, &$3, &$5, 1);
499                             }
500                     | INSTR_M4x4 omods dreg ',' sregs
501                             {
502                                 TRACE("M4x4\n");
503                                 asm_ctx.funcs->instr(&asm_ctx, BWRITERSIO_M4x4, $2.mod, $2.shift, 0, &$3, &$5, 2);
504                             }
505                     | INSTR_M4x3 omods dreg ',' sregs
506                             {
507                                 TRACE("M4x3\n");
508                                 asm_ctx.funcs->instr(&asm_ctx, BWRITERSIO_M4x3, $2.mod, $2.shift, 0, &$3, &$5, 2);
509                             }
510                     | INSTR_M3x4 omods dreg ',' sregs
511                             {
512                                 TRACE("M3x4\n");
513                                 asm_ctx.funcs->instr(&asm_ctx, BWRITERSIO_M3x4, $2.mod, $2.shift, 0, &$3, &$5, 2);
514                             }
515                     | INSTR_M3x3 omods dreg ',' sregs
516                             {
517                                 TRACE("M3x3\n");
518                                 asm_ctx.funcs->instr(&asm_ctx, BWRITERSIO_M3x3, $2.mod, $2.shift, 0, &$3, &$5, 2);
519                             }
520                     | INSTR_M3x2 omods dreg ',' sregs
521                             {
522                                 TRACE("M3x2\n");
523                                 asm_ctx.funcs->instr(&asm_ctx, BWRITERSIO_M3x2, $2.mod, $2.shift, 0, &$3, &$5, 2);
524                             }
525                     | INSTR_DCL dclusage REG_OUTPUT
526                             {
527                                 struct shader_reg reg;
528                                 TRACE("Output reg declaration\n");
529                                 ZeroMemory(&reg, sizeof(reg));
530                                 reg.type = BWRITERSPR_OUTPUT;
531                                 reg.regnum = $3;
532                                 reg.rel_reg = NULL;
533                                 reg.srcmod = 0;
534                                 reg.writemask = BWRITERSP_WRITEMASK_ALL;
535                                 asm_ctx.funcs->dcl_output(&asm_ctx, $2.dclusage, $2.regnum, &reg);
536                             }
537                     | INSTR_DCL dclusage REG_OUTPUT writemask
538                             {
539                                 struct shader_reg reg;
540                                 TRACE("Output reg declaration\n");
541                                 ZeroMemory(&reg, sizeof(reg));
542                                 reg.type = BWRITERSPR_OUTPUT;
543                                 reg.regnum = $3;
544                                 reg.rel_reg = NULL;
545                                 reg.srcmod = 0;
546                                 reg.writemask = $4;
547                                 asm_ctx.funcs->dcl_output(&asm_ctx, $2.dclusage, $2.regnum, &reg);
548                             }
549                     | INSTR_DCL dclusage REG_INPUT
550                             {
551                                 struct shader_reg reg;
552                                 TRACE("Input reg declaration\n");
553                                 ZeroMemory(&reg, sizeof(reg));
554                                 reg.type = BWRITERSPR_INPUT;
555                                 reg.regnum = $3;
556                                 reg.rel_reg = NULL;
557                                 reg.srcmod = 0;
558                                 reg.writemask = BWRITERSP_WRITEMASK_ALL;
559                                 asm_ctx.funcs->dcl_input(&asm_ctx, $2.dclusage, $2.regnum, &reg);
560                             }
561                     | INSTR_DCL dclusage REG_INPUT writemask
562                             {
563                                 struct shader_reg reg;
564                                 TRACE("Input reg declaration\n");
565                                 ZeroMemory(&reg, sizeof(reg));
566                                 reg.type = BWRITERSPR_INPUT;
567                                 reg.regnum = $3;
568                                 reg.rel_reg = NULL;
569                                 reg.srcmod = 0;
570                                 reg.writemask = $4;
571                                 asm_ctx.funcs->dcl_input(&asm_ctx, $2.dclusage, $2.regnum, &reg);
572                             }
573                     | INSTR_DCL sampdcl REG_SAMPLER
574                             {
575                                 TRACE("Sampler declared\n");
576                                 asm_ctx.funcs->dcl_sampler(&asm_ctx, $2, $3, asm_ctx.line_no);
577                             }
578                     | INSTR_DCL sampdcl REG_INPUT
579                             {
580                                 TRACE("Error rule: sampler decl of input reg\n");
581                                 asmparser_message(&asm_ctx, "Line %u: Sampler declarations of input regs is not valid\n",
582                                                   asm_ctx.line_no);
583                                 set_parse_status(&asm_ctx, PARSE_WARN);
584                             }
585                     | INSTR_DCL sampdcl REG_OUTPUT
586                             {
587                                 TRACE("Error rule: sampler decl of output reg\n");
588                                 asmparser_message(&asm_ctx, "Line %u: Sampler declarations of output regs is not valid\n",
589                                                   asm_ctx.line_no);
590                                 set_parse_status(&asm_ctx, PARSE_WARN);
591                             }
592                     | INSTR_DEF REG_CONSTFLOAT ',' IMMVAL ',' IMMVAL ',' IMMVAL ',' IMMVAL
593                             {
594                                 asm_ctx.funcs->constF(&asm_ctx, $2, $4.val, $6.val, $8.val, $10.val);
595                             }
596                     | INSTR_DEFI REG_CONSTINT ',' IMMVAL ',' IMMVAL ',' IMMVAL ',' IMMVAL
597                             {
598                                 asm_ctx.funcs->constI(&asm_ctx, $2, $4.val, $6.val, $8.val, $10.val);
599                             }
600                     | INSTR_DEFB REG_CONSTBOOL ',' IMMBOOL
601                             {
602                                 asm_ctx.funcs->constB(&asm_ctx, $2, $4);
603                             }
604                     | INSTR_REP sregs
605                             {
606                                 TRACE("REP\n");
607                                 asm_ctx.funcs->instr(&asm_ctx, BWRITERSIO_REP, 0, 0, 0, 0, &$2, 1);
608                             }
609                     | INSTR_ENDREP
610                             {
611                                 TRACE("ENDREP\n");
612                                 asm_ctx.funcs->instr(&asm_ctx, BWRITERSIO_ENDREP, 0, 0, 0, 0, 0, 0);
613                             }
614                     | INSTR_IF sregs
615                             {
616                                 TRACE("IF\n");
617                                 asm_ctx.funcs->instr(&asm_ctx, BWRITERSIO_IF, 0, 0, 0, 0, &$2, 1);
618                             }
619                     | INSTR_IF comp sregs
620                             {
621                                 TRACE("IFC\n");
622                                 asm_ctx.funcs->instr(&asm_ctx, BWRITERSIO_IFC, 0, 0, $2, 0, &$3, 2);
623                             }
624                     | INSTR_ELSE
625                             {
626                                 TRACE("ELSE\n");
627                                 asm_ctx.funcs->instr(&asm_ctx, BWRITERSIO_ELSE, 0, 0, 0, 0, 0, 0);
628                             }
629                     | INSTR_ENDIF
630                             {
631                                 TRACE("ENDIF\n");
632                                 asm_ctx.funcs->instr(&asm_ctx, BWRITERSIO_ENDIF, 0, 0, 0, 0, 0, 0);
633                             }
634                     | INSTR_BREAK
635                             {
636                                 TRACE("BREAK\n");
637                                 asm_ctx.funcs->instr(&asm_ctx, BWRITERSIO_BREAK, 0, 0, 0, 0, 0, 0);
638                             }
639                     | INSTR_BREAK comp sregs
640                             {
641                                 TRACE("BREAKC\n");
642                                 asm_ctx.funcs->instr(&asm_ctx, BWRITERSIO_BREAKC, 0, 0, $2, 0, &$3, 2);
643                             }
644                     | INSTR_BREAKP sregs
645                             {
646                                 TRACE("BREAKP\n");
647                                 asm_ctx.funcs->instr(&asm_ctx, BWRITERSIO_BREAKP, 0, 0, 0, 0, &$2, 1);
648                             }
649                     | INSTR_CALL sregs
650                             {
651                                 TRACE("CALL\n");
652                                 asm_ctx.funcs->instr(&asm_ctx, BWRITERSIO_CALL, 0, 0, 0, 0, &$2, 1);
653                             }
654                     | INSTR_CALLNZ sregs
655                             {
656                                 TRACE("CALLNZ\n");
657                                 asm_ctx.funcs->instr(&asm_ctx, BWRITERSIO_CALLNZ, 0, 0, 0, 0, &$2, 2);
658                             }
659                     | INSTR_LOOP sregs
660                             {
661                                 TRACE("LOOP\n");
662                                 asm_ctx.funcs->instr(&asm_ctx, BWRITERSIO_LOOP, 0, 0, 0, 0, &$2, 2);
663                             }
664                     | INSTR_RET
665                             {
666                                 TRACE("RET\n");
667                                 asm_ctx.funcs->instr(&asm_ctx, BWRITERSIO_RET, 0, 0, 0, 0, 0, 0);
668                             }
669                     | INSTR_ENDLOOP
670                             {
671                                 TRACE("ENDLOOP\n");
672                                 asm_ctx.funcs->instr(&asm_ctx, BWRITERSIO_ENDLOOP, 0, 0, 0, 0, 0, 0);
673                             }
674                     | INSTR_LABEL sregs
675                             {
676                                 TRACE("LABEL\n");
677                                 asm_ctx.funcs->instr(&asm_ctx, BWRITERSIO_LABEL, 0, 0, 0, 0, &$2, 1);
678                             }
679                     | INSTR_SETP comp dreg ',' sregs
680                             {
681                                 TRACE("SETP\n");
682                                 asm_ctx.funcs->instr(&asm_ctx, BWRITERSIO_SETP, 0, 0, $2, &$3, &$5, 2);
683                             }
684                     | INSTR_TEXLDL omods dreg ',' sregs
685                             {
686                                 TRACE("TEXLDL\n");
687                                 asm_ctx.funcs->instr(&asm_ctx, BWRITERSIO_TEXLDL, $2.mod, $2.shift, 0, &$3, &$5, 2);
688                             }
689                     | INSTR_LIT omods dreg ',' sregs
690                             {
691                                 TRACE("LIT\n");
692                                 asm_ctx.funcs->instr(&asm_ctx, BWRITERSIO_LIT, $2.mod, $2.shift, 0, &$3, &$5, 1);
693                             }
694                     | INSTR_MOVA omods dreg ',' sregs
695                             {
696                                 TRACE("MOVA\n");
697                                 asm_ctx.funcs->instr(&asm_ctx, BWRITERSIO_MOVA, $2.mod, $2.shift, 0, &$3, &$5, 1);
698                             }
699                     | INSTR_CMP omods dreg ',' sregs
700                             {
701                                 TRACE("CMP\n");
702                                 asm_ctx.funcs->instr(&asm_ctx, BWRITERSIO_CMP, $2.mod, $2.shift, 0, &$3, &$5, 3);
703                             }
704                     | INSTR_DP2ADD omods dreg ',' sregs
705                             {
706                                 TRACE("DP2ADD\n");
707                                 asm_ctx.funcs->instr(&asm_ctx, BWRITERSIO_DP2ADD, $2.mod, $2.shift, 0, &$3, &$5, 3);
708                             }
709                     | INSTR_TEXLD omods dreg ',' sregs
710                             {
711                                 TRACE("TEXLD\n");
712                                 /* There is more than one acceptable syntax for texld:
713                                    with 1 sreg (PS 1.4) or
714                                    with 2 sregs (PS 2.0+)
715                                    Moreover, texld shares the same opcode as the tex instruction,
716                                    so there are a total of 3 valid syntaxes
717                                    These variations are handled in asmparser.c */
718                                 asm_ctx.funcs->instr(&asm_ctx, BWRITERSIO_TEX, $2.mod, $2.shift, 0, &$3, &$5, 2);
719                             }
720                     | INSTR_TEXLDP omods dreg ',' sregs
721                             {
722                                 TRACE("TEXLDP\n");
723                                 asm_ctx.funcs->instr(&asm_ctx, BWRITERSIO_TEX | ( BWRITERSI_TEXLD_PROJECT << BWRITER_OPCODESPECIFICCONTROL_SHIFT ), $2.mod, $2.shift, 0, &$3, &$5, 2);
724                             }
725                     | INSTR_TEXLDB omods dreg ',' sregs
726                             {
727                                 TRACE("TEXLDB\n");
728                                 asm_ctx.funcs->instr(&asm_ctx, BWRITERSIO_TEX | ( BWRITERSI_TEXLD_BIAS << BWRITER_OPCODESPECIFICCONTROL_SHIFT ), $2.mod, $2.shift, 0, &$3, &$5, 2);
729                             }
730                     | INSTR_DSX omods dreg ',' sregs
731                             {
732                                 TRACE("DSX\n");
733                                 asm_ctx.funcs->instr(&asm_ctx, BWRITERSIO_DSX, $2.mod, $2.shift, 0, &$3, &$5, 1);
734                             }
735                     | INSTR_DSY omods dreg ',' sregs
736                             {
737                                 TRACE("DSY\n");
738                                 asm_ctx.funcs->instr(&asm_ctx, BWRITERSIO_DSY, $2.mod, $2.shift, 0, &$3, &$5, 1);
739                             }
740                     | INSTR_TEXLDD omods dreg ',' sregs
741                             {
742                                 TRACE("TEXLDD\n");
743                                 asm_ctx.funcs->instr(&asm_ctx, BWRITERSIO_TEXLDD, $2.mod, $2.shift, 0, &$3, &$5, 4);
744                             }
745
746 dreg:                 dreg_name rel_reg
747                             {
748                                 $$.regnum = $1.regnum;
749                                 $$.type = $1.type;
750                                 $$.writemask = BWRITERSP_WRITEMASK_ALL;
751                                 $$.srcmod = BWRITERSPSM_NONE;
752                                 set_rel_reg(&$$, &$2);
753                             }
754                     | dreg_name writemask
755                             {
756                                 $$.regnum = $1.regnum;
757                                 $$.type = $1.type;
758                                 $$.writemask = $2;
759                                 $$.srcmod = BWRITERSPSM_NONE;
760                                 $$.rel_reg = NULL;
761                             }
762
763 dreg_name:            REG_TEMP
764                         {
765                             $$.regnum = $1; $$.type = BWRITERSPR_TEMP;
766                         }
767                     | REG_OUTPUT
768                         {
769                             $$.regnum = $1; $$.type = BWRITERSPR_OUTPUT;
770                         }
771                     | REG_INPUT
772                         {
773                             asmparser_message(&asm_ctx, "Line %u: Register v%u is not a valid destination register\n",
774                                               asm_ctx.line_no, $1);
775                             set_parse_status(&asm_ctx, PARSE_WARN);
776                         }
777                     | REG_CONSTFLOAT
778                         {
779                             asmparser_message(&asm_ctx, "Line %u: Register c%u is not a valid destination register\n",
780                                               asm_ctx.line_no, $1);
781                             set_parse_status(&asm_ctx, PARSE_WARN);
782                         }
783                     | REG_CONSTINT
784                         {
785                           asmparser_message(&asm_ctx, "Line %u: Register i%u is not a valid destination register\n",
786                                               asm_ctx.line_no, $1);
787                             set_parse_status(&asm_ctx, PARSE_WARN);
788                         }
789                     | REG_CONSTBOOL
790                         {
791                             asmparser_message(&asm_ctx, "Line %u: Register b%u is not a valid destination register\n",
792                                               asm_ctx.line_no, $1);
793                             set_parse_status(&asm_ctx, PARSE_WARN);
794                         }
795                     | REG_TEXTURE
796                         {
797                             $$.regnum = $1; $$.type = BWRITERSPR_TEXTURE;
798                         }
799                     | REG_TEXCRDOUT
800                         {
801                             $$.regnum = $1; $$.type = BWRITERSPR_TEXCRDOUT;
802                         }
803                     | REG_SAMPLER
804                         {
805                             asmparser_message(&asm_ctx, "Line %u: Register s%u is not a valid destination register\n",
806                                               asm_ctx.line_no, $1);
807                             set_parse_status(&asm_ctx, PARSE_WARN);
808                         }
809                     | REG_OPOS
810                         {
811                             $$.regnum = BWRITERSRO_POSITION; $$.type = BWRITERSPR_RASTOUT;
812                         }
813                     | REG_OPTS
814                         {
815                             $$.regnum = BWRITERSRO_POINT_SIZE; $$.type = BWRITERSPR_RASTOUT;
816                         }
817                     | REG_OFOG
818                         {
819                             $$.regnum = BWRITERSRO_FOG; $$.type = BWRITERSPR_RASTOUT;
820                         }
821                     | REG_VERTEXCOLOR
822                         {
823                             $$.regnum = $1; $$.type = BWRITERSPR_ATTROUT;
824                         }
825                     | REG_FRAGCOLOR
826                         {
827                             $$.regnum = $1; $$.type = BWRITERSPR_COLOROUT;
828                         }
829                     | REG_FRAGDEPTH
830                         {
831                             $$.regnum = 0; $$.type = BWRITERSPR_DEPTHOUT;
832                         }
833                     | REG_PREDICATE
834                         {
835                             $$.regnum = 0; $$.type = BWRITERSPR_PREDICATE;
836                         }
837                     | REG_VPOS
838                         {
839                             asmparser_message(&asm_ctx, "Line %u: Register vPos is not a valid destination register\n",
840                                               asm_ctx.line_no);
841                             set_parse_status(&asm_ctx, PARSE_WARN);
842                         }
843                     | REG_VFACE
844                         {
845                             asmparser_message(&asm_ctx, "Line %u: Register vFace is not a valid destination register\n",
846                                               asm_ctx.line_no);
847                             set_parse_status(&asm_ctx, PARSE_WARN);
848                         }
849                     | REG_ADDRESS
850                         {
851                             /* index 0 is hardcoded for the addr register */
852                             $$.regnum = 0; $$.type = BWRITERSPR_ADDR;
853                         }
854                     | REG_LOOP
855                         {
856                             asmparser_message(&asm_ctx, "Line %u: Register aL is not a valid destination register\n",
857                                               asm_ctx.line_no);
858                             set_parse_status(&asm_ctx, PARSE_WARN);
859                         }
860
861 writemask:            '.' wm_components
862                         {
863                             if($2.writemask == SWIZZLE_ERR) {
864                                 asmparser_message(&asm_ctx, "Line %u: Invalid writemask specified\n",
865                                                   asm_ctx.line_no);
866                                 set_parse_status(&asm_ctx, PARSE_ERR);
867                                 /* Provide a correct writemask to prevent following complaints */
868                                 $$ = BWRITERSP_WRITEMASK_ALL;
869                             }
870                             else {
871                                 $$ = $2.writemask;
872                                 TRACE("Writemask: %x\n", $$);
873                             }
874                         }
875
876 wm_components:        COMPONENT
877                         {
878                             $$.writemask = 1 << $1;
879                             $$.last = $1;
880                             $$.idx = 1;
881                         }
882                     | wm_components COMPONENT
883                         {
884                             if($1.writemask == SWIZZLE_ERR || $1.idx == 4)
885                                 /* Wrong writemask */
886                                 $$.writemask = SWIZZLE_ERR;
887                             else {
888                                 if($2 <= $1.last)
889                                     $$.writemask = SWIZZLE_ERR;
890                                 else {
891                                     $$.writemask = $1.writemask | (1 << $2);
892                                     $$.idx = $1.idx + 1;
893                                 }
894                             }
895                         }
896
897 swizzle:              /* empty */
898                         {
899                             $$ = BWRITERVS_NOSWIZZLE;
900                             TRACE("Default swizzle: %08x\n", $$);
901                         }
902                     | '.' sw_components
903                         {
904                             if($2.swizzle == SWIZZLE_ERR) {
905                                 asmparser_message(&asm_ctx, "Line %u: Invalid swizzle\n",
906                                                   asm_ctx.line_no);
907                                 set_parse_status(&asm_ctx, PARSE_ERR);
908                                 /* Provide a correct swizzle to prevent following complaints */
909                                 $$ = BWRITERVS_NOSWIZZLE;
910                             }
911                             else {
912                                 DWORD last, i;
913
914                                 $$ = $2.swizzle << BWRITERVS_SWIZZLE_SHIFT;
915                                 /* Fill the swizzle by extending the last component */
916                                 last = ($2.swizzle >> 2 * ($2.idx - 1)) & 0x03;
917                                 for(i = $2.idx; i < 4; i++){
918                                     $$ |= last << (BWRITERVS_SWIZZLE_SHIFT + 2 * i);
919                                 }
920                                 TRACE("Got a swizzle: %08x\n", $$);
921                             }
922                         }
923
924 sw_components:        COMPONENT
925                         {
926                             $$.swizzle = $1;
927                             $$.idx = 1;
928                         }
929                     | sw_components COMPONENT
930                         {
931                             if($1.idx == 4) {
932                                 /* Too many sw_components */
933                                 $$.swizzle = SWIZZLE_ERR;
934                                 $$.idx = 4;
935                             }
936                             else {
937                                 $$.swizzle = $1.swizzle | ($2 << 2 * $1.idx);
938                                 $$.idx = $1.idx + 1;
939                             }
940                         }
941
942 omods:                 /* Empty */
943                         {
944                             $$.mod = 0;
945                             $$.shift = 0;
946                         }
947                     | omods omodifier
948                         {
949                             $$.mod = $1.mod | $2.mod;
950                             if($1.shift && $2.shift) {
951                                 asmparser_message(&asm_ctx, "Line %u: More than one shift flag\n",
952                                                   asm_ctx.line_no);
953                                 set_parse_status(&asm_ctx, PARSE_ERR);
954                                 $$.shift = $1.shift;
955                             } else {
956                                 $$.shift = $1.shift | $2.shift;
957                             }
958                         }
959
960 omodifier:            MOD_SAT
961                         {
962                             $$.mod = BWRITERSPDM_SATURATE;
963                             $$.shift = 0;
964                         }
965                     | MOD_PP
966                         {
967                             $$.mod = BWRITERSPDM_PARTIALPRECISION;
968                             $$.shift = 0;
969                         }
970                     | MOD_CENTROID
971                         {
972                             $$.mod = BWRITERSPDM_MSAMPCENTROID;
973                             $$.shift = 0;
974                         }
975
976 sregs:                sreg
977                         {
978                             $$.reg[0] = $1;
979                             $$.count = 1;
980                         }
981                     | sregs ',' sreg
982                         {
983                             if($$.count == MAX_SRC_REGS){
984                                 asmparser_message(&asm_ctx, "Line %u: Too many source registers in this instruction\n",
985                                                   asm_ctx.line_no);
986                                 set_parse_status(&asm_ctx, PARSE_ERR);
987                             }
988                             else
989                                 $$.reg[$$.count++] = $3;
990                         }
991
992 sreg:                   sreg_name rel_reg swizzle
993                         {
994                             $$.type = $1.type;
995                             $$.regnum = $1.regnum;
996                             $$.swizzle = $3;
997                             $$.srcmod = BWRITERSPSM_NONE;
998                             set_rel_reg(&$$, &$2);
999                         }
1000                     | sreg_name rel_reg smod swizzle
1001                         {
1002                             $$.type = $1.type;
1003                             $$.regnum = $1.regnum;
1004                             set_rel_reg(&$$, &$2);
1005                             $$.srcmod = $3;
1006                             $$.swizzle = $4;
1007                         }
1008                     | '-' sreg_name rel_reg swizzle
1009                         {
1010                             $$.type = $2.type;
1011                             $$.regnum = $2.regnum;
1012                             $$.srcmod = BWRITERSPSM_NEG;
1013                             set_rel_reg(&$$, &$3);
1014                             $$.swizzle = $4;
1015                         }
1016                     | '-' sreg_name rel_reg smod swizzle
1017                         {
1018                             $$.type = $2.type;
1019                             $$.regnum = $2.regnum;
1020                             set_rel_reg(&$$, &$3);
1021                             switch($4) {
1022                                 case BWRITERSPSM_ABS:  $$.srcmod = BWRITERSPSM_ABSNEG;  break;
1023                                 default:
1024                                     FIXME("Unhandled combination of NEGATE and %u\n", $4);
1025                             }
1026                             $$.swizzle = $5;
1027                         }
1028                     | SMOD_NOT sreg_name swizzle
1029                         {
1030                             $$.type = $2.type;
1031                             $$.regnum = $2.regnum;
1032                             $$.rel_reg = NULL;
1033                             $$.srcmod = BWRITERSPSM_NOT;
1034                             $$.swizzle = $3;
1035                         }
1036
1037 rel_reg:               /* empty */
1038                         {
1039                             $$.has_rel_reg = FALSE;
1040                             $$.additional_offset = 0;
1041                         }
1042                     | '[' immsum ']'
1043                         {
1044                             $$.has_rel_reg = FALSE;
1045                             $$.additional_offset = $2.val;
1046                         }
1047                     | '[' relreg_name swizzle ']'
1048                         {
1049                             $$.has_rel_reg = TRUE;
1050                             $$.type = $2.type;
1051                             $$.additional_offset = 0;
1052                             $$.rel_regnum = $2.regnum;
1053                             $$.swizzle = $3;
1054                         }
1055                     | '[' immsum '+' relreg_name swizzle ']'
1056                         {
1057                             $$.has_rel_reg = TRUE;
1058                             $$.type = $4.type;
1059                             $$.additional_offset = $2.val;
1060                             $$.rel_regnum = $4.regnum;
1061                             $$.swizzle = $5;
1062                         }
1063                     | '[' relreg_name swizzle '+' immsum ']'
1064                         {
1065                             $$.has_rel_reg = TRUE;
1066                             $$.type = $2.type;
1067                             $$.additional_offset = $5.val;
1068                             $$.rel_regnum = $2.regnum;
1069                             $$.swizzle = $3;
1070                         }
1071                     | '[' immsum '+' relreg_name swizzle '+' immsum ']'
1072                         {
1073                             $$.has_rel_reg = TRUE;
1074                             $$.type = $4.type;
1075                             $$.additional_offset = $2.val + $7.val;
1076                             $$.rel_regnum = $4.regnum;
1077                             $$.swizzle = $5;
1078                         }
1079
1080 immsum:               IMMVAL
1081                         {
1082                             if(!$1.integer) {
1083                                 asmparser_message(&asm_ctx, "Line %u: Unexpected float %f\n",
1084                                                   asm_ctx.line_no, $1.val);
1085                                 set_parse_status(&asm_ctx, PARSE_ERR);
1086                             }
1087                             $$.val = $1.val;
1088                         }
1089                     | immsum '+' IMMVAL
1090                         {
1091                             if(!$3.integer) {
1092                                 asmparser_message(&asm_ctx, "Line %u: Unexpected float %f\n",
1093                                                   asm_ctx.line_no, $3.val);
1094                                 set_parse_status(&asm_ctx, PARSE_ERR);
1095                             }
1096                             $$.val = $1.val + $3.val;
1097                         }
1098
1099 smod:                 SMOD_ABS
1100                         {
1101                             $$ = BWRITERSPSM_ABS;
1102                         }
1103
1104 relreg_name:          REG_ADDRESS
1105                         {
1106                             $$.regnum = 0; $$.type = BWRITERSPR_ADDR;
1107                         }
1108                     | REG_LOOP
1109                         {
1110                             $$.regnum = 0; $$.type = BWRITERSPR_LOOP;
1111                         }
1112
1113 sreg_name:            REG_TEMP
1114                         {
1115                             $$.regnum = $1; $$.type = BWRITERSPR_TEMP;
1116                         }
1117                     | REG_OUTPUT
1118                         {
1119                             asmparser_message(&asm_ctx, "Line %u: Register o%u is not a valid source register\n",
1120                                               asm_ctx.line_no, $1);
1121                             set_parse_status(&asm_ctx, PARSE_WARN);
1122                         }
1123                     | REG_INPUT
1124                         {
1125                             $$.regnum = $1; $$.type = BWRITERSPR_INPUT;
1126                         }
1127                     | REG_CONSTFLOAT
1128                         {
1129                             $$.regnum = $1; $$.type = BWRITERSPR_CONST;
1130                         }
1131                     | REG_CONSTINT
1132                         {
1133                             $$.regnum = $1; $$.type = BWRITERSPR_CONSTINT;
1134                         }
1135                     | REG_CONSTBOOL
1136                         {
1137                             $$.regnum = $1; $$.type = BWRITERSPR_CONSTBOOL;
1138                         }
1139                     | REG_TEXTURE
1140                         {
1141                             $$.regnum = $1; $$.type = BWRITERSPR_TEXTURE;
1142                         }
1143                     | REG_TEXCRDOUT
1144                         {
1145                             asmparser_message(&asm_ctx, "Line %u: Register oT%u is not a valid source register\n",
1146                                               asm_ctx.line_no, $1);
1147                             set_parse_status(&asm_ctx, PARSE_WARN);
1148                         }
1149                     | REG_SAMPLER
1150                         {
1151                             $$.regnum = $1; $$.type = BWRITERSPR_SAMPLER;
1152                         }
1153                     | REG_OPOS
1154                         {
1155                             asmparser_message(&asm_ctx, "Line %u: Register oPos is not a valid source register\n",
1156                                               asm_ctx.line_no);
1157                             set_parse_status(&asm_ctx, PARSE_WARN);
1158                         }
1159                     | REG_OFOG
1160                         {
1161                             asmparser_message(&asm_ctx, "Line %u: Register oFog is not a valid source register\n",
1162                                               asm_ctx.line_no);
1163                             set_parse_status(&asm_ctx, PARSE_WARN);
1164                         }
1165                     | REG_VERTEXCOLOR
1166                         {
1167                             asmparser_message(&asm_ctx, "Line %u: Register oD%u is not a valid source register\n",
1168                                               asm_ctx.line_no, $1);
1169                             set_parse_status(&asm_ctx, PARSE_WARN);
1170                         }
1171                     | REG_FRAGCOLOR
1172                         {
1173                             asmparser_message(&asm_ctx, "Line %u: Register oC%u is not a valid source register\n",
1174                                               asm_ctx.line_no, $1);
1175                             set_parse_status(&asm_ctx, PARSE_WARN);
1176                         }
1177                     | REG_FRAGDEPTH
1178                         {
1179                             asmparser_message(&asm_ctx, "Line %u: Register oDepth is not a valid source register\n",
1180                                               asm_ctx.line_no);
1181                             set_parse_status(&asm_ctx, PARSE_WARN);
1182                         }
1183                     | REG_PREDICATE
1184                         {
1185                             $$.regnum = 0; $$.type = BWRITERSPR_PREDICATE;
1186                         }
1187                     | REG_VPOS
1188                         {
1189                             $$.regnum = 0; $$.type = BWRITERSPR_MISCTYPE;
1190                         }
1191                     | REG_VFACE
1192                         {
1193                             $$.regnum = 1; $$.type = BWRITERSPR_MISCTYPE;
1194                         }
1195                     | REG_ADDRESS
1196                         {
1197                             $$.regnum = 0; $$.type = BWRITERSPR_ADDR;
1198                         }
1199                     | REG_LOOP
1200                         {
1201                             $$.regnum = 0; $$.type = BWRITERSPR_LOOP;
1202                         }
1203                     | REG_LABEL
1204                         {
1205                             $$.regnum = $1; $$.type = BWRITERSPR_LABEL;
1206                         }
1207
1208 comp:                 COMP_GT           { $$ = BWRITER_COMPARISON_GT;       }
1209                     | COMP_LT           { $$ = BWRITER_COMPARISON_LT;       }
1210                     | COMP_GE           { $$ = BWRITER_COMPARISON_GE;       }
1211                     | COMP_LE           { $$ = BWRITER_COMPARISON_LE;       }
1212                     | COMP_EQ           { $$ = BWRITER_COMPARISON_EQ;       }
1213                     | COMP_NE           { $$ = BWRITER_COMPARISON_NE;       }
1214
1215 dclusage:             USAGE_POSITION
1216                         {
1217                             TRACE("dcl_position%u\n", $1);
1218                             $$.regnum = $1;
1219                             $$.dclusage = BWRITERDECLUSAGE_POSITION;
1220                         }
1221                     | USAGE_BLENDWEIGHT
1222                         {
1223                             TRACE("dcl_blendweight%u\n", $1);
1224                             $$.regnum = $1;
1225                             $$.dclusage = BWRITERDECLUSAGE_BLENDWEIGHT;
1226                         }
1227                     | USAGE_BLENDINDICES
1228                         {
1229                             TRACE("dcl_blendindices%u\n", $1);
1230                             $$.regnum = $1;
1231                             $$.dclusage = BWRITERDECLUSAGE_BLENDINDICES;
1232                         }
1233                     | USAGE_NORMAL
1234                         {
1235                             TRACE("dcl_normal%u\n", $1);
1236                             $$.regnum = $1;
1237                             $$.dclusage = BWRITERDECLUSAGE_NORMAL;
1238                         }
1239                     | USAGE_PSIZE
1240                         {
1241                             TRACE("dcl_psize%u\n", $1);
1242                             $$.regnum = $1;
1243                             $$.dclusage = BWRITERDECLUSAGE_PSIZE;
1244                         }
1245                     | USAGE_TEXCOORD
1246                         {
1247                             TRACE("dcl_texcoord%u\n", $1);
1248                             $$.regnum = $1;
1249                             $$.dclusage = BWRITERDECLUSAGE_TEXCOORD;
1250                         }
1251                     | USAGE_TANGENT
1252                         {
1253                             TRACE("dcl_tangent%u\n", $1);
1254                             $$.regnum = $1;
1255                             $$.dclusage = BWRITERDECLUSAGE_TANGENT;
1256                         }
1257                     | USAGE_BINORMAL
1258                         {
1259                             TRACE("dcl_binormal%u\n", $1);
1260                             $$.regnum = $1;
1261                             $$.dclusage = BWRITERDECLUSAGE_BINORMAL;
1262                         }
1263                     | USAGE_TESSFACTOR
1264                         {
1265                             TRACE("dcl_tessfactor%u\n", $1);
1266                             $$.regnum = $1;
1267                             $$.dclusage = BWRITERDECLUSAGE_TESSFACTOR;
1268                         }
1269                     | USAGE_POSITIONT
1270                         {
1271                             TRACE("dcl_positiont%u\n", $1);
1272                             $$.regnum = $1;
1273                             $$.dclusage = BWRITERDECLUSAGE_POSITIONT;
1274                         }
1275                     | USAGE_COLOR
1276                         {
1277                             TRACE("dcl_color%u\n", $1);
1278                             $$.regnum = $1;
1279                             $$.dclusage = BWRITERDECLUSAGE_COLOR;
1280                         }
1281                     | USAGE_FOG
1282                         {
1283                             TRACE("dcl_fog%u\n", $1);
1284                             $$.regnum = $1;
1285                             $$.dclusage = BWRITERDECLUSAGE_FOG;
1286                         }
1287                     | USAGE_DEPTH
1288                         {
1289                             TRACE("dcl_depth%u\n", $1);
1290                             $$.regnum = $1;
1291                             $$.dclusage = BWRITERDECLUSAGE_DEPTH;
1292                         }
1293                     | USAGE_SAMPLE
1294                         {
1295                             TRACE("dcl_sample%u\n", $1);
1296                             $$.regnum = $1;
1297                             $$.dclusage = BWRITERDECLUSAGE_SAMPLE;
1298                         }
1299
1300 sampdcl:              SAMPTYPE_1D
1301                         {
1302                             $$ = BWRITERSTT_1D;
1303                         }
1304                     | SAMPTYPE_2D
1305                         {
1306                             $$ = BWRITERSTT_2D;
1307                         }
1308                     | SAMPTYPE_CUBE
1309                         {
1310                             $$ = BWRITERSTT_CUBE;
1311                         }
1312                     | SAMPTYPE_VOLUME
1313                         {
1314                             $$ = BWRITERSTT_VOLUME;
1315                         }
1316
1317 predicate:            '(' REG_PREDICATE swizzle ')'
1318                         {
1319                             $$.type = BWRITERSPR_PREDICATE;
1320                             $$.regnum = 0;
1321                             $$.rel_reg = NULL;
1322                             $$.srcmod = BWRITERSPSM_NONE;
1323                             $$.swizzle = $3;
1324                         }
1325                     | '(' SMOD_NOT REG_PREDICATE swizzle ')'
1326                         {
1327                             $$.type = BWRITERSPR_PREDICATE;
1328                             $$.regnum = 0;
1329                             $$.rel_reg = NULL;
1330                             $$.srcmod = BWRITERSPSM_NOT;
1331                             $$.swizzle = $4;
1332                         }
1333
1334 %%
1335
1336 void asmshader_error (char const *s) {
1337     asmparser_message(&asm_ctx, "Line %u: Error \"%s\" from bison\n", asm_ctx.line_no, s);
1338     set_parse_status(&asm_ctx, PARSE_ERR);
1339 }
1340
1341 /* Error reporting function */
1342 void asmparser_message(struct asm_parser *ctx, const char *fmt, ...) {
1343     va_list args;
1344     char* newbuffer;
1345     int rc, newsize;
1346
1347     if(ctx->messagecapacity == 0) {
1348         ctx->messages = asm_alloc(MESSAGEBUFFER_INITIAL_SIZE);
1349         if(ctx->messages == NULL) {
1350             ERR("Error allocating memory for parser messages\n");
1351             return;
1352         }
1353         ctx->messagecapacity = MESSAGEBUFFER_INITIAL_SIZE;
1354     }
1355
1356     while(1) {
1357         va_start(args, fmt);
1358         rc = vsnprintf(ctx->messages + ctx->messagesize,
1359                        ctx->messagecapacity - ctx->messagesize, fmt, args);
1360         va_end(args);
1361
1362         if (rc < 0 ||                                           /* C89 */
1363             rc >= ctx->messagecapacity - ctx->messagesize) {    /* C99 */
1364             /* Resize the buffer */
1365             newsize = ctx->messagecapacity * 2;
1366             newbuffer = asm_realloc(ctx->messages, newsize);
1367             if(newbuffer == NULL){
1368                 ERR("Error reallocating memory for parser messages\n");
1369                 return;
1370             }
1371             ctx->messages = newbuffer;
1372             ctx->messagecapacity = newsize;
1373         } else {
1374             ctx->messagesize += rc;
1375             return;
1376         }
1377     }
1378 }
1379
1380 /* New status is the worst between current status and parameter value */
1381 void set_parse_status(struct asm_parser *ctx, enum parse_status status) {
1382     if(status == PARSE_ERR) ctx->status = PARSE_ERR;
1383     else if(status == PARSE_WARN && ctx->status == PARSE_SUCCESS) ctx->status = PARSE_WARN;
1384 }
1385
1386 struct bwriter_shader *parse_asm_shader(char **messages) {
1387     struct bwriter_shader *ret = NULL;
1388
1389     asm_ctx.shader = NULL;
1390     asm_ctx.status = PARSE_SUCCESS;
1391     asm_ctx.messagesize = asm_ctx.messagecapacity = 0;
1392     asm_ctx.line_no = 1;
1393
1394     asmshader_parse();
1395
1396     if(asm_ctx.status != PARSE_ERR) ret = asm_ctx.shader;
1397     else if(asm_ctx.shader) SlDeleteShader(asm_ctx.shader);
1398
1399     if(messages) {
1400         if(asm_ctx.messagesize) {
1401             /* Shrink the buffer to the used size */
1402             *messages = asm_realloc(asm_ctx.messages, asm_ctx.messagesize + 1);
1403             if(!*messages) {
1404                 ERR("Out of memory, no messages reported\n");
1405                 asm_free(asm_ctx.messages);
1406             }
1407         } else {
1408             *messages = NULL;
1409         }
1410     } else {
1411         if(asm_ctx.messagecapacity) asm_free(asm_ctx.messages);
1412     }
1413
1414     return ret;
1415 }