updated gpdf2swf (patch from Ricardo Pedroso)
[swftools.git] / lib / action / swf5compiler.y
1 /* $Id: swf5compiler.y,v 1.2 2008/10/28 13:05:13 kramm Exp $ */
2
3 %start program
4
5 %{
6
7 #include <time.h>
8 #include <string.h>
9 #include <stdlib.h>
10 #include "compile.h"
11 #include "action.h"
12 #include "assembler.h"
13
14 #define YYPARSE_PARAM buffer
15
16 Buffer bf, bc;
17
18 %}
19
20 %union
21 {
22   Buffer action;
23   char *str;
24   SWFGetUrl2Method getURLMethod;
25   int op;
26   int intVal;
27   int len;
28   double doubleVal;
29
30   struct
31   {
32     Buffer buffer;
33     int count;
34   } exprlist;
35   struct switchcase   switchcase;
36   struct switchcases switchcases;
37   struct
38   {
39         Buffer obj, ident, memexpr;
40   } lval;
41 }
42
43 /* tokens etc. */
44
45 %token BREAK CONTINUE FUNCTION ELSE SWITCH CASE DEFAULT FOR IN IF WHILE
46 %token DO VAR NEW DELETE RETURN END WITH ASM EVAL
47
48 %token RANDOM GETTIMER LENGTH CONCAT SUBSTR TRACE INT ORD CHR GETURL
49 %token GETURL1 NEXTFRAME PREVFRAME PLAY STOP TOGGLEQUALITY STOPSOUNDS
50
51 %token DUP SWAP POP PUSH SETREGISTER CALLFUNCTION CALLMETHOD
52 %token AND OR XOR MODULO ADD LESSTHAN EQUALS
53 %token INC DEC TYPEOF INSTANCEOF ENUMERATE INITOBJECT INITARRAY GETMEMBER
54 %token SETMEMBER SHIFTLEFT SHIFTRIGHT SHIFTRIGHT2 VAREQUALS OLDADD SUBTRACT
55 %token MULTIPLY DIVIDE OLDEQUALS OLDLESSTHAN LOGICALAND LOGICALOR NOT
56 %token STRINGEQ STRINGLENGTH SUBSTRING GETVARIABLE SETVARIABLE
57 %token SETTARGETEXPRESSION  DUPLICATEMOVIECLIP REMOVEMOVIECLIP
58 %token STRINGLESSTHAN MBLENGTH MBSUBSTRING MBORD MBCHR
59 %token BRANCHALWAYS BRANCHIFTRUE GETURL2 POST GET
60 %token LOADVARIABLES LOADMOVIE LOADVARIABLESNUM LOADMOVIENUM
61 %token CALLFRAME STARTDRAG STOPDRAG GOTOFRAME SETTARGET
62
63 %token NULLVAL
64 %token <intVal> INTEGER
65 %token <doubleVal> DOUBLE
66 %token <intVal> BOOLEAN
67 %token <str> REGISTER
68
69 /* these two are strdup'ed in compiler.flex, so free them up here */
70 %token <str> STRING
71 %token <str> IDENTIFIER
72
73 %token EQ "=="
74 %token LE "<="
75 %token GE ">="
76 %token NE "!="
77 %token LAN "&&"
78 %token LOR "||"
79 %token INCR "++"
80 %token DECR "--"
81 %token IEQ "+="
82 %token DEQ "/="
83 %token MEQ "*="
84 %token SEQ "-="
85 %token REQ "%="
86 %token AEQ "&="
87 %token OEQ "|="
88
89 %token SHL "<<"
90 %token SHR ">>"
91 %token SHR2 ">>>"
92 %token SHLEQ "<<="
93 %token SHREQ ">>="
94 %token SHR2EQ ">>>="
95
96
97 /* ascending order of ops ..? */
98
99 %nonassoc NOELSE
100 %nonassoc ELSE
101 %left ','
102 %right '=' "*=" "/=" "%=" "+=" "-=" "&=" "|=" "^=" ">>=" ">>>=" "<<="
103 %right '?' ':'
104 %left "&&" "||"
105 %left "==" "!="
106 %left '<' '>' "<=" ">="
107 %left '&' '|' '^'
108 %left "<<" ">>" ">>>"
109 %left '+' '-'
110 %left '*' '/' '%'
111 %nonassoc "++" "--"
112 %right '!' '~' UMINUS
113 %right POSTFIX
114 %right TYPEOF
115 %nonassoc INSTANCEOF
116 %left '.' '[' ']'
117
118
119 %type <action> program code
120 %type <action> stmt stmts
121 %type <action> if_stmt iter_stmt cont_stmt break_stmt return_stmt
122 %type <action> with_stmt
123 %type <action> switch_stmt
124 %type <action> anon_function_decl function_decl anycode
125 %type <action> void_function_call function_call method_call
126 %type <action> assign_stmt assign_stmts assign_stmts_opt
127 %type <action> expr expr_or_obj objexpr expr_opt obj_ref
128 %type <action> emptybraces level init_vars init_var primary lvalue_expr
129 %type <lval> lvalue
130
131 %type <exprlist> expr_list objexpr_list formals_list
132
133 %type <switchcase> switch_case
134 %type <switchcases> switch_cases
135
136 %type <op> assignop incdecop
137 %type <getURLMethod> urlmethod
138
139 %type <str> identifier
140
141 %type <len> opcode opcode_list push_item with push_list
142
143 /*
144 %type <intVal> integer
145 %type <doubleVal> double
146 */
147 %%
148
149 /* rules */
150
151 program
152         : { bf = newBuffer();
153                 bc = newBuffer();
154         } code
155                 { Buffer b = newBuffer();
156                   bufferWriteConstants(b);
157                   bufferConcat(b, bf);
158                   bufferConcat(b, bc);
159                   *((Buffer *)buffer) = b; }
160         | /* nothing */ { Buffer b = newBuffer(); *((Buffer *)buffer) = b; }
161         ;
162
163 code
164         : anycode
165         | code anycode
166         ;
167
168 anycode
169         : stmt
170                 { bufferConcat(bc, $1); }
171         | function_decl
172                 { bufferConcat(bf, $1); }
173         ;
174
175 stmts
176         : stmt
177                 { $$ = $1; }
178
179         | stmts stmt
180                 { $$ = $1;
181                   bufferConcat($$, $2); }
182         ;
183
184 emptybraces
185         : '{' '}'       { }
186         ;
187
188 stmt
189         : emptybraces                           { $$ = NULL; }
190         | '{' stmts '}'                         { $$ = $2; }
191         | ';'                                   { $$ = NULL; }
192         | assign_stmt ';'                       { $$ = $1; }
193         | if_stmt
194         | iter_stmt
195         | cont_stmt
196         | break_stmt
197         | switch_stmt
198         | return_stmt
199         | with_stmt
200         ;
201
202 with_stmt
203         : WITH '(' expr ')' '{' stmts '}'
204                 { $$ = $3;
205                   bufferWriteOp($$, SWFACTION_WITH);
206                   bufferWriteS16($$, 2);
207                   bufferWriteS16($$, bufferLength($6));
208                   bufferConcat($$, $6); }
209         ;
210
211 // only possible if there is an active CTX_FUNCTION
212 // in some contexts, may have to pop a few values ...
213 return_stmt
214         : RETURN ';'
215                 { int tmp = chkctx(CTX_FUNCTION);
216                   if(tmp < 0)
217                         swf5error("return outside function");
218                   $$ = newBuffer();
219                   while(--tmp >= 0)
220                         bufferWriteOp($$, SWFACTION_POP);
221                   bufferWriteNull($$);
222                   bufferWriteOp($$, SWFACTION_RETURN); }
223
224         | RETURN expr_or_obj ';'
225                 { int tmp = chkctx(CTX_FUNCTION);
226                   if(tmp < 0)
227                         swf5error("return outside function");
228                   $$ = newBuffer();
229                   while(--tmp >= 0)
230                         bufferWriteOp($$, SWFACTION_POP);
231                   bufferConcat($$, $2);
232                   bufferWriteOp($$, SWFACTION_RETURN); }
233         ;
234
235 assign_stmts
236         : assign_stmt
237         | assign_stmts ',' assign_stmt          { bufferConcat($1, $3); }
238         ;
239
240 if_stmt
241         : IF '(' expr ')' stmt ELSE stmt
242                 { $$ = $3;
243                   bufferWriteOp($$, SWFACTION_BRANCHIFTRUE);
244                   bufferWriteS16($$, 2);
245                   bufferWriteS16($$, bufferLength($7)+5);
246                   bufferConcat($$, $7);
247                   bufferWriteOp($$, SWFACTION_BRANCHALWAYS);
248                   bufferWriteS16($$, 2);
249                   bufferWriteS16($$, bufferLength($5));
250                   bufferConcat($$, $5); }
251
252         | IF '(' expr ')' stmt          %prec NOELSE
253                 { $$ = $3;
254                   bufferWriteOp($$, SWFACTION_LOGICALNOT);
255                   bufferWriteOp($$, SWFACTION_BRANCHIFTRUE);
256                   bufferWriteS16($$, 2);
257                   bufferWriteS16($$, bufferLength($5));
258                   bufferConcat($$, $5); }
259         ;
260
261 expr_opt
262         : /* empty */   { $$ = NULL; }
263         | expr          { $$ = $1; }
264         ;
265
266 switch_init
267         : SWITCH
268                 { addctx(CTX_SWITCH); }
269         ;
270
271 switch_stmt
272         : switch_init '(' expr ')' '{'
273           switch_cases '}'
274                 { $$ = $3;
275                   bufferResolveSwitch($$, &$6);
276                   bufferResolveJumps($$);
277                   bufferWriteOp($$, SWFACTION_POP);
278                   delctx(CTX_SWITCH);
279  /* FIXME: continue in switch continues surrounding loop, if any */
280         }
281         ;
282
283 /* XXX */
284 switch_cases
285         : /* empty */
286                 { $$.count = 0;
287                   $$.list = 0; }
288
289         | switch_cases switch_case
290                 { $$ = $1;
291                   $$.list = (struct switchcase*) realloc($$.list, ($$.count+1) * sizeof(struct switchcase));
292                   $$.list[$$.count] = $2;
293                   $$.count++; }
294         ;
295
296 switch_case
297         : CASE expr ':' stmts BREAK ';'
298                 { $$.cond = $2;
299                   $$.action = $4;
300                   $$.isbreak = 1; }
301
302         | CASE expr ':' stmts
303                 { $$.cond = $2;
304                   $$.action = $4;
305                   $$.isbreak = 0; }
306
307         | DEFAULT ':' stmts
308                 { $$.cond = NULL;
309                   $$.action = $3;
310                   $$.isbreak = 0; }
311         ;
312
313
314 /* there's GOT to be a better way than this.. */
315
316 identifier
317         : IDENTIFIER
318         | NEW           { $$ = strdup("new"); }
319         | DELETE        { $$ = strdup("delete"); }
320         | RANDOM        { $$ = strdup("random"); }
321         | GETTIMER      { $$ = strdup("getTimer"); }
322         | LENGTH        { $$ = strdup("length"); }
323         | CONCAT        { $$ = strdup("concat"); }
324         | SUBSTR        { $$ = strdup("substr"); }
325         | TRACE { $$ = strdup("trace"); }
326         | INT   { $$ = strdup("int"); }
327         | ORD   { $$ = strdup("ord"); }
328         | CHR   { $$ = strdup("chr"); }
329         | GETURL        { $$ = strdup("getURL"); }
330         | GETURL1       { $$ = strdup("getURL1"); }
331         | NEXTFRAME     { $$ = strdup("nextFrame"); }
332         | PREVFRAME     { $$ = strdup("prevFrame"); }
333         | PLAY  { $$ = strdup("play"); }
334         | STOP  { $$ = strdup("stop"); }
335         | TOGGLEQUALITY { $$ = strdup("toggleQuality"); }
336         | STOPSOUNDS    { $$ = strdup("stopSounds"); }
337         | DUP   { $$ = strdup("dup"); }
338         | SWAP  { $$ = strdup("swap"); }
339         | POP   { $$ = strdup("pop"); }
340         | PUSH  { $$ = strdup("push"); }
341         | SETREGISTER   { $$ = strdup("setRegister"); }
342         | CALLFUNCTION  { $$ = strdup("callFunction"); }
343         | CALLMETHOD    { $$ = strdup("callMethod"); }
344         | AND   { $$ = strdup("and"); }
345         | OR    { $$ = strdup("or"); }
346         | XOR   { $$ = strdup("xor"); }
347         | MODULO        { $$ = strdup("modulo"); }
348         | ADD   { $$ = strdup("add"); }
349         | LESSTHAN      { $$ = strdup("lessThan"); }
350         | EQUALS        { $$ = strdup("equals"); }
351         | INC   { $$ = strdup("inc"); }
352         | DEC   { $$ = strdup("dec"); }
353         | TYPEOF        { $$ = strdup("typeof"); }
354         | INSTANCEOF    { $$ = strdup("instanceof"); }
355         | ENUMERATE     { $$ = strdup("enumerate"); }
356         | INITOBJECT    { $$ = strdup("initobject"); }
357         | INITARRAY     { $$ = strdup("initarray"); }
358         | GETMEMBER     { $$ = strdup("getmember"); }
359         | SETMEMBER     { $$ = strdup("setmember"); }
360         | SHIFTLEFT     { $$ = strdup("shiftleft"); }
361         | SHIFTRIGHT    { $$ = strdup("shiftright"); }
362         | SHIFTRIGHT2   { $$ = strdup("shiftright2"); }
363         | VAREQUALS     { $$ = strdup("varequals"); }
364         | OLDADD        { $$ = strdup("oldAdd"); }
365         | SUBTRACT      { $$ = strdup("subtract"); }
366         | MULTIPLY      { $$ = strdup("multiply"); }
367         | DIVIDE        { $$ = strdup("divide"); }
368         | OLDEQUALS     { $$ = strdup("oldequals"); }
369         | OLDLESSTHAN   { $$ = strdup("oldlessthan"); }
370         | LOGICALAND    { $$ = strdup("logicaland"); }
371         | LOGICALOR     { $$ = strdup("logicalor"); }
372         | NOT   { $$ = strdup("not"); }
373         | STRINGEQ      { $$ = strdup("stringeq"); }
374         | STRINGLENGTH  { $$ = strdup("stringlength"); }
375         | SUBSTRING     { $$ = strdup("substring"); }
376         | GETVARIABLE   { $$ = strdup("getvariable"); }
377         | SETVARIABLE   { $$ = strdup("setvariable"); }
378         | SETTARGETEXPRESSION   { $$ = strdup("settargetexpression"); }
379         | DUPLICATEMOVIECLIP    { $$ = strdup("duplicatemovieclip"); }
380         | REMOVEMOVIECLIP       { $$ = strdup("removemovieclip"); }
381         | STARTDRAG     { $$ = strdup("startdrag"); }
382         | STOPDRAG      { $$ = strdup("stopdrag"); }
383         | STRINGLESSTHAN        { $$ = strdup("stringlessthan"); }
384         | MBLENGTH      { $$ = strdup("mblength"); }
385         | MBSUBSTRING   { $$ = strdup("mbsubstring"); }
386         | MBORD { $$ = strdup("mbord"); }
387         | MBCHR { $$ = strdup("mbchr"); }
388         | BRANCHALWAYS  { $$ = strdup("branchalways"); }
389         | BRANCHIFTRUE  { $$ = strdup("branchiftrue"); }
390         | GETURL2       { $$ = strdup("getURL2"); }
391         | POST  { $$ = strdup("post"); }
392         | GET   { $$ = strdup("get"); }
393         | LOADVARIABLES { $$ = strdup("loadvariables"); }
394         | LOADMOVIE     { $$ = strdup("loadMovie"); }
395         ;
396
397 formals_list
398         : /* empty */
399                 { $$.buffer = newBuffer();
400                   $$.count = 0; }
401
402         | identifier
403                 { $$.buffer = newBuffer();
404                   bufferWriteHardString($$.buffer, (byte*)$1, strlen($1)+1);
405                   $$.count = 1; }
406
407         | formals_list ',' identifier
408                 { $$ = $1;
409                   bufferWriteHardString($$.buffer, (byte*)$3, strlen($3)+1);
410                   ++$$.count; }
411         ;
412
413 function_init
414         : FUNCTION
415                 { addctx(CTX_FUNCTION); }
416         ;
417
418 function_decl
419         : function_init identifier '(' formals_list ')' stmt
420                 { $$ = newBuffer();
421                   bufferWriteOp($$, SWFACTION_DEFINEFUNCTION);
422                   bufferWriteS16($$, strlen($2) +
423                                      bufferLength($4.buffer) + 5);
424                   bufferWriteHardString($$, (byte*) $2, strlen($2)+1);
425                   bufferWriteS16($$, $4.count);
426                   bufferConcat($$, $4.buffer);
427                   bufferWriteS16($$, bufferLength($6));
428                   bufferConcat($$, $6);
429                   delctx(CTX_FUNCTION); }
430         ;
431
432 obj_ref
433         : identifier
434                 { $$ = newBuffer();
435                   bufferWriteString($$, $1, strlen($1)+1);
436                   free($1); }
437
438         | expr '.' identifier
439                 { $$ = $1;
440                   bufferWriteString($$, $3, strlen($3)+1);
441                   bufferWriteOp($$, SWFACTION_GETMEMBER);
442                   free($3); }
443
444         | expr '[' expr ']'
445                 { $$ = $1;
446                   bufferConcat($$, $3);
447                   bufferWriteOp($$, SWFACTION_GETMEMBER); }
448
449         | function_call
450
451         | method_call
452         ;
453
454 while_init
455         : WHILE
456                 { addctx(CTX_LOOP); }
457         ;
458
459 do_init
460         : DO
461                 { addctx(CTX_LOOP); }
462         ;
463
464 for_init
465         : /* empty */
466                 { addctx(CTX_LOOP); }
467         ;
468
469 for_in_init
470         : /* empty */
471                 { addctx(CTX_FOR_IN); }
472         ;
473
474 iter_stmt
475         : while_init '(' expr ')' stmt
476                 { $$ = $3;
477                   bufferWriteOp($$, SWFACTION_LOGICALNOT);
478                   bufferWriteOp($$, SWFACTION_BRANCHIFTRUE);
479                   bufferWriteS16($$, 2);
480                   bufferWriteS16($$, bufferLength($5)+5);
481                   bufferConcat($$, $5);
482                   bufferWriteOp($$, SWFACTION_BRANCHALWAYS);
483                   bufferWriteS16($$, 2);
484                   bufferWriteS16($$, -(bufferLength($$)+2));
485                   bufferResolveJumps($$);
486                   delctx(CTX_LOOP); }
487
488         | do_init stmt WHILE '(' expr ')'
489                 { if($2)
490                         {       $$ = $2;
491                                 bufferConcat($$, $5);
492                         }
493                         else
494                                 $$ = $5;
495                   bufferWriteOp($$, SWFACTION_BRANCHIFTRUE);
496                   bufferWriteS16($$, 2);
497                   bufferWriteS16($$, -(bufferLength($$)+2));
498                   bufferResolveJumps($$);
499                   delctx(CTX_LOOP); }
500
501         | FOR '(' assign_stmts_opt ';' expr_opt ';' assign_stmts_opt ')' for_init stmt
502                 {
503                   if($3)
504                     $$ = $3;
505                   else
506                     $$ = newBuffer();
507
508                   if($7)
509                   {
510                     bufferWriteOp($$, SWFACTION_BRANCHALWAYS);
511                     bufferWriteS16($$, 2);
512                     bufferWriteS16($$, bufferLength($7));
513                   }
514                   else
515                     $7 = newBuffer();
516
517                   if($5)
518                   {
519                     bufferConcat($7, $5);
520                     bufferWriteOp($7, SWFACTION_LOGICALNOT);
521                     bufferWriteOp($7, SWFACTION_BRANCHIFTRUE);
522                     bufferWriteS16($7, 2);
523                     bufferWriteS16($7, bufferLength($10)+5);
524                   }
525
526                   bufferConcat($7, $10);
527                   bufferWriteOp($7, SWFACTION_BRANCHALWAYS);
528                   bufferWriteS16($7, 2);
529                   bufferWriteS16($7, -(bufferLength($7)+2));
530                   bufferResolveJumps($7);
531
532                   bufferConcat($$, $7);
533                                   delctx(CTX_LOOP);
534                 }
535
536         | FOR '(' identifier IN obj_ref ')' for_in_init stmt
537                 { Buffer b2, b3;
538                   int tmp;
539
540                   $$ = $5;
541                   bufferWriteOp($$, SWFACTION_ENUMERATE);       
542
543                   b2 = newBuffer();
544                   bufferWriteSetRegister(b2, 0);
545                   bufferWriteOp(b2, SWFACTION_PUSHDATA);
546                   bufferWriteS16(b2, 1);
547                   bufferWriteU8(b2, 2);
548                   bufferWriteOp(b2, SWFACTION_NEWEQUALS);
549                   bufferWriteOp(b2, SWFACTION_BRANCHIFTRUE);
550                   bufferWriteS16(b2, 2);
551
552                   b3 = newBuffer();
553 /* basically a lvalue could be used here rather than an ident !!! */
554 /* probably by using reg1 for the test rather than reg0 */
555                   bufferWriteString(b3, $3, strlen($3)+1);
556                   bufferWriteRegister(b3, 0);
557                   bufferWriteOp(b3, SWFACTION_SETVARIABLE);
558                   bufferConcat(b3, $8);
559                   bufferWriteS16(b2, bufferLength(b3) + 5);
560                   tmp = bufferLength(b2) + bufferLength(b3) + 5;
561                   bufferConcat($$, b2);
562                   bufferWriteOp(b3, SWFACTION_BRANCHALWAYS);
563                   bufferWriteS16(b3, 2);
564                   bufferWriteS16(b3, -tmp);
565                   bufferResolveJumps(b3);
566                   bufferConcat($$, b3);
567                   delctx(CTX_FOR_IN); }
568
569         | FOR '(' VAR identifier IN obj_ref ')' for_in_init stmt
570                 { Buffer b2, b3;
571                   int tmp;
572
573                   $$ = $6;
574                   bufferWriteOp($$, SWFACTION_ENUMERATE);       
575
576                   b2 = newBuffer();
577                   bufferWriteSetRegister(b2, 0);
578                   bufferWriteOp(b2, SWFACTION_PUSHDATA);
579                   bufferWriteS16(b2, 1);
580                   bufferWriteU8(b2, 2);
581                   bufferWriteOp(b2, SWFACTION_NEWEQUALS);
582                   bufferWriteOp(b2, SWFACTION_BRANCHIFTRUE);
583                   bufferWriteS16(b2, 2);
584                   // add size later
585
586                   b3 = newBuffer();
587                   bufferWriteString(b3, $4, strlen($4)+1);
588                   bufferWriteRegister(b3, 0);
589                   bufferWriteOp(b3, SWFACTION_VAREQUALS);
590                   bufferConcat(b3, $9);
591                   bufferWriteS16(b2, bufferLength(b3) + 5);
592                   tmp = bufferLength(b2) + bufferLength(b3) + 5;
593                   bufferConcat($$, b2);
594                   bufferWriteOp(b3, SWFACTION_BRANCHALWAYS);
595                   bufferWriteS16(b3, 2);
596                   bufferWriteS16(b3, -tmp);
597                   bufferResolveJumps(b3);
598                   bufferConcat($$, b3);
599                   delctx(CTX_FOR_IN); }
600         ;
601
602 assign_stmts_opt
603         : /* empty */                           { $$ = NULL; }
604         | assign_stmts
605         ;
606
607 // continue only makes sense if there is a CTX_LOOP or CTX_FOR_IN
608 // on the stack
609 cont_stmt
610         : CONTINUE ';'
611                 { if(chkctx(CTX_CONTINUE) < 0)
612                         swf5error("continue outside loop");
613                   $$ = newBuffer();
614                   bufferWriteOp($$, SWFACTION_BRANCHALWAYS);
615                   bufferWriteS16($$, 2);
616                   bufferWriteS16($$, MAGIC_CONTINUE_NUMBER); }
617         ;
618
619 // break is possible if there is a CTX_LOOP, CTX_FOR_IN or CTX_SWITCH
620 break_stmt
621         : BREAK ';'
622                 { int tmp = chkctx(CTX_BREAK);
623                   if(tmp < 0)
624                         swf5error("break outside switch / loop");
625                   $$ = newBuffer();
626                   if(tmp)       /* break out of a for .. in */
627                         bufferWriteOp($$, SWFACTION_POP);
628                   bufferWriteOp($$, SWFACTION_BRANCHALWAYS);
629                   bufferWriteS16($$, 2);
630                   bufferWriteS16($$, MAGIC_BREAK_NUMBER); }
631         ;
632
633 urlmethod
634         : /* empty */           { $$ = GETURL_METHOD_NOSEND; }
635
636         | ',' GET               { $$ = GETURL_METHOD_GET; }
637
638         | ',' POST              { $$ = GETURL_METHOD_POST; }
639
640         | ',' STRING            { if(strcmp($2, "GET") == 0)
641                                     $$ = GETURL_METHOD_GET;
642                                   else if(strcmp($2, "POST") == 0)
643                                     $$ = GETURL_METHOD_POST; }
644         ;
645
646 level
647         : INTEGER
648                 { char *lvlstring = (char*) malloc(12*sizeof(char));
649                   sprintf(lvlstring, "_level%d", $1);
650                   $$ = newBuffer();
651                   bufferWriteString($$, lvlstring, strlen(lvlstring)+1);
652                   free(lvlstring); }
653
654         | expr
655                 { $$ = newBuffer();
656                   bufferWriteString($$, "_level", 7);
657                   bufferConcat($$, $1);
658                   bufferWriteOp($$, SWFACTION_STRINGCONCAT); }
659         ;
660
661 void_function_call
662         : IDENTIFIER '(' expr_list ')'
663                 { $$ = $3.buffer;
664                   bufferWriteInt($$, $3.count);
665                   bufferWriteString($$, $1, strlen($1)+1);
666                   bufferWriteOp($$, SWFACTION_CALLFUNCTION);
667                   bufferWriteOp($$, SWFACTION_POP);
668                   free($1); }
669
670         | DELETE IDENTIFIER
671                 { $$ = newBuffer();
672                   bufferWriteString($$, $2, strlen($2)+1);
673                   free($2);
674                   bufferWriteOp($$, SWFACTION_DELETE); }
675
676         | DELETE lvalue_expr '.' IDENTIFIER
677                 { $$ = $2;
678                   // bufferWriteOp($$, SWFACTION_GETVARIABLE);
679                   bufferWriteString($$, $4, strlen($4)+1);
680                   free($4);
681                   bufferWriteOp($$, SWFACTION_DELETEVAR); }
682
683         | DELETE lvalue_expr '[' expr ']'
684                 { $$ = $2;
685                   // bufferWriteOp($$, SWFACTION_GETVARIABLE);
686                   bufferConcat($$, $4);
687                   // bufferWriteOp($$, SWFACTION_GETVARIABLE);
688                   bufferWriteOp($$, SWFACTION_DELETEVAR); }
689
690         | TRACE '(' expr_or_obj ')'
691                 { $$ = $3;
692                   bufferWriteOp($$, SWFACTION_TRACE); }
693
694         | GETURL '(' expr ',' expr urlmethod ')'
695                 { $$ = $3;
696                   bufferConcat($$, $5);
697                   bufferWriteOp($$, SWFACTION_GETURL2);
698                   bufferWriteS16($$, 1);
699                   bufferWriteU8($$, $6); }
700
701         | LOADVARIABLES '(' expr ',' expr urlmethod ')'
702                 { $$ = $3;
703                   bufferConcat($$, $5);
704                   bufferWriteOp($$, SWFACTION_GETURL2);
705                   bufferWriteS16($$, 1);
706                   bufferWriteU8($$, 0xc0+$6); }
707
708         | LOADVARIABLESNUM '(' expr ',' level urlmethod ')'
709                 { $$ = $3;
710                   bufferConcat($$, $5);
711                   bufferWriteOp($$, SWFACTION_GETURL2);
712                   bufferWriteS16($$, 1);
713                   bufferWriteU8($$, 0x80+$6); }
714
715         | LOADMOVIE '(' expr ',' expr urlmethod ')'
716                 { $$ = $3;
717                   bufferConcat($$, $5);
718                   bufferWriteOp($$, SWFACTION_GETURL2);
719                   bufferWriteS16($$, 1);
720                   bufferWriteU8($$, 0x40+$6); }
721
722         | LOADMOVIENUM '(' expr ',' level urlmethod ')'
723                 { $$ = $3;
724                   bufferConcat($$, $5);
725                   bufferWriteOp($$, SWFACTION_GETURL2);
726                   bufferWriteS16($$, 1);
727                   bufferWriteU8($$, $6); }
728
729         | CALLFRAME '(' expr ')'
730                 { $$ = $3;
731                   bufferWriteOp($$, SWFACTION_CALLFRAME);
732                   bufferWriteS16($$, 0); }
733
734         /* startDrag(target, lock, [left, right, top, bottom]) */
735         | STARTDRAG '(' expr ',' expr ')'
736                 { $$ = newBuffer();
737                   bufferWriteString($$, "0", 2); /* no constraint */
738                   bufferConcat($$, $5);
739                   bufferConcat($$, $3);
740                   bufferWriteOp($$, SWFACTION_STARTDRAGMOVIE); }
741
742         | STARTDRAG '(' expr ',' expr ',' expr ',' expr ',' expr ',' expr ')'
743                 { $$ = newBuffer();
744                   bufferConcat($$, $7);
745                   bufferConcat($$, $11);
746                   bufferConcat($$, $9);
747                   bufferConcat($$, $13);
748                   bufferWriteString($$, "1", 2); /* has constraint */
749                   bufferConcat($$, $5);
750                   bufferConcat($$, $3);
751                   bufferWriteOp($$, SWFACTION_STARTDRAGMOVIE); }
752
753         | STOPDRAG '(' ')' /* no args */
754                 { $$ = newBuffer();
755                   bufferWriteOp($$, SWFACTION_STOPDRAGMOVIE); }
756
757         /* duplicateMovieClip(target, new, depth) */
758         | DUPLICATEMOVIECLIP '(' expr ',' expr ',' expr ')'
759                 { $$ = $3;
760                   bufferConcat($$, $5);
761                   bufferConcat($$, $7);
762                   bufferWriteInt($$, 16384); /* magic number */
763                   bufferWriteOp($$, SWFACTION_ADD);
764                   bufferWriteOp($$, SWFACTION_DUPLICATECLIP); }
765
766         | REMOVEMOVIECLIP '(' expr ')'
767                 { $$ = $3;
768                   bufferWriteOp($$, SWFACTION_REMOVECLIP); }
769
770         | GETURL1 '(' STRING ',' STRING ')'
771                 { $$ = newBuffer();
772                   bufferWriteOp($$, SWFACTION_GETURL);
773                   bufferWriteS16($$, strlen($3) + strlen($5) + 2);
774                   bufferWriteHardString($$, (byte*)$3, strlen($3));
775                   bufferWriteU8($$, 0);
776                   bufferWriteHardString($$, (byte*)$5, strlen($5));
777                   bufferWriteU8($$, 0); }
778
779         /* v3 actions */
780         | NEXTFRAME '(' ')'
781                 { $$ = newBuffer();
782                   bufferWriteOp($$, SWFACTION_NEXTFRAME); }
783                 
784         | PREVFRAME '(' ')'
785                 { $$ = newBuffer();
786                   bufferWriteOp($$, SWFACTION_PREVFRAME); }
787
788         | PLAY '(' ')'
789                 { $$ = newBuffer();
790                   bufferWriteOp($$, SWFACTION_PLAY); }
791
792         | STOP '(' ')'
793                 { $$ = newBuffer();
794                   bufferWriteOp($$, SWFACTION_STOP); }
795
796         | STOPSOUNDS '(' ')'
797                 { $$ = newBuffer();
798                   bufferWriteOp($$, SWFACTION_STOPSOUNDS); }
799
800         | TOGGLEQUALITY '(' ')'
801                 { $$ = newBuffer();
802                   bufferWriteOp($$, SWFACTION_TOGGLEQUALITY); }
803
804         | GOTOFRAME '(' INTEGER ')'
805                 { $$ = newBuffer();
806                   bufferWriteOp($$, SWFACTION_GOTOFRAME);
807                   bufferWriteS16($$, 2);
808                   bufferWriteS16($$, $3); }
809
810         | GOTOFRAME '(' STRING ')'
811                 { $$ = newBuffer();
812                   bufferWriteOp($$, SWFACTION_GOTOLABEL);
813                   bufferWriteS16($$, strlen($3)+1);
814                   bufferWriteHardString($$, (byte*)$3, strlen($3)+1);
815                   free($3); }
816
817         | GOTOFRAME '(' expr ')'
818                 { $$ = $3;
819                   bufferWriteOp($$, SWFACTION_GOTOEXPRESSION);
820                   bufferWriteS16($$, 1);
821                   bufferWriteU8($$, 0); } /* XXX - and stop */
822
823         | SETTARGET '(' STRING ')'
824                 { $$ = newBuffer();
825                   bufferWriteOp($$, SWFACTION_SETTARGET);
826                   bufferWriteS16($$, strlen($3)+1);
827                   bufferWriteHardString($$, (byte*)$3, strlen($3)+1);
828                   free($3); }
829
830         | SETTARGET '(' expr ')'
831                 { $$ = $3;
832                   bufferWriteOp($$, SWFACTION_SETTARGETEXPRESSION); }
833
834
835         ;
836
837
838 function_call
839         : IDENTIFIER '(' expr_list ')'
840                 { $$ = $3.buffer;
841                   bufferWriteInt($$, $3.count);
842                   bufferWriteString($$, $1, strlen($1)+1);
843                   bufferWriteOp($$, SWFACTION_CALLFUNCTION);
844                   free($1); }
845
846         | EVAL '(' expr ')'
847                 { $$ = $3;
848                   bufferWriteOp($$, SWFACTION_GETVARIABLE); }
849
850         | GETTIMER '(' ')'
851                 { $$ = newBuffer();
852                   bufferWriteOp($$, SWFACTION_GETTIMER); }
853
854         | RANDOM '(' expr ')'
855                 { $$ = $3;
856                   bufferWriteOp($$, SWFACTION_RANDOM); }
857
858         | LENGTH '(' expr_or_obj ')'
859                 { $$ = $3;
860                   bufferWriteOp($$, SWFACTION_STRINGLENGTH); }
861
862         | INT '(' expr ')'
863                 { $$ = $3;
864                   bufferWriteOp($$, SWFACTION_INT); }
865
866         | ORD '(' expr ')'
867                 { $$ = $3;
868                   bufferWriteOp($$, SWFACTION_ORD); }
869
870         | CHR '(' expr ')'
871                 { $$ = $3;
872                   bufferWriteOp($$, SWFACTION_CHR); }
873
874         | CONCAT '(' expr ',' expr ')'
875                 { $$ = $3;
876                   bufferConcat($$, $5);
877                   bufferWriteOp($$, SWFACTION_STRINGCONCAT); }
878
879         | SUBSTRING '(' expr ',' expr ',' expr ')'
880                 { $$ = $3;
881                   bufferConcat($$, $5);
882                   bufferConcat($$, $7);
883                   bufferWriteOp($$, SWFACTION_SUBSTRING); }
884
885         | TYPEOF '(' expr_or_obj ')'
886                 { $$ = $3;
887                   bufferWriteOp($$, SWFACTION_TYPEOF); }
888
889         ;
890
891
892 expr_list
893         : /* empty */
894                 { $$.buffer = newBuffer();
895                   $$.count = 0; }
896
897         | expr_or_obj
898                 { $$.buffer = $1;
899                   $$.count = 1; }
900
901         /* goes backwards. rrgh. */
902         | expr_list ',' expr_or_obj
903                 { Buffer tmp = newBuffer();
904                   bufferConcat(tmp, $3);
905                   bufferConcat(tmp, $$.buffer);
906                   $$.buffer = tmp;
907                   ++$$.count;  }
908         ;
909
910 anon_function_decl
911         : function_init '(' formals_list ')' stmt
912                 { $$ = newBuffer();
913                   bufferWriteOp($$, SWFACTION_DEFINEFUNCTION);
914                   bufferWriteS16($$, bufferLength($3.buffer) + 5);
915                   bufferWriteU8($$, 0); /* empty function name */
916                   bufferWriteS16($$, $3.count);
917                   bufferConcat($$, $3.buffer);
918                   bufferWriteS16($$, bufferLength($5));
919                   bufferConcat($$, $5);
920                   delctx(CTX_FUNCTION); }
921         ;
922
923 method_call
924         : lvalue_expr '.' identifier '(' expr_list ')'
925                 { $$ = $5.buffer;
926                   bufferWriteInt($$, $5.count);
927                   bufferConcat($$, $1);
928                   bufferWriteString($$, $3, strlen($3)+1);
929                   bufferWriteOp($$, SWFACTION_CALLMETHOD);
930                   free($3); }
931
932         | lvalue_expr '[' expr ']' '(' expr_list ')'
933                 { $$ = $6.buffer;
934                   bufferWriteInt($$, $6.count);
935                   bufferConcat($$, $1);
936                   bufferConcat($$, $3);
937                   bufferWriteOp($$, SWFACTION_CALLMETHOD); }
938         ;
939
940 objexpr
941         : identifier ':' expr_or_obj
942                 { $$ = newBuffer();
943                   bufferWriteString($$, $1, strlen($1)+1);
944                   bufferConcat($$, $3); }
945         ;
946
947 objexpr_list
948         : objexpr
949                 { $$.buffer = $1;
950                   $$.count = 1; }
951
952         | objexpr_list ',' objexpr
953                 { bufferConcat($$.buffer, $3);
954                   ++$$.count;  }
955         ;
956
957 assignop
958         : "+="          { $$ = SWFACTION_NEWADD; }
959         | "-="          { $$ = SWFACTION_SUBTRACT; }
960         | "*="          { $$ = SWFACTION_MULTIPLY; }
961         | "/="          { $$ = SWFACTION_DIVIDE; }
962         | "%="          { $$ = SWFACTION_MODULO; }
963         | "&="          { $$ = SWFACTION_BITWISEAND; }
964         | "|="          { $$ = SWFACTION_BITWISEOR; }
965         | "^="          { $$ = SWFACTION_BITWISEXOR; }
966         | "<<="         { $$ = SWFACTION_SHIFTLEFT; }
967         | ">>="         { $$ = SWFACTION_SHIFTRIGHT; }
968         | ">>>="        { $$ = SWFACTION_SHIFTRIGHT2; }
969         ;
970
971 incdecop
972         : "++"          { $$ = SWFACTION_INCREMENT; }
973         | "--"          { $$ = SWFACTION_DECREMENT; }
974         ;
975
976
977 /*
978 integer
979         : '-' INTEGER %prec UMINUS      { $$ = -$2; }
980         | INTEGER                       { $$ = $1; }
981         ;
982
983 double
984         : '-' DOUBLE %prec UMINUS       { $$ = -$2; }
985         | DOUBLE                        { $$ = $1; }
986         ;
987 */
988
989 /* resolves an lvalue into a buffer */
990 lvalue_expr
991         : lvalue
992                 { if($1.obj)
993                   {
994                     $$ = $1.obj;
995
996                     if($1.ident)
997                       bufferConcat($$, $1.ident);
998                     else
999                       bufferConcat($$, $1.memexpr);
1000
1001                     bufferWriteOp($$, SWFACTION_GETMEMBER);
1002                   }
1003                   else
1004                   {
1005                     $$ = $1.ident;
1006                     bufferWriteOp($$, SWFACTION_GETVARIABLE);
1007                   }
1008                 }
1009         | function_call
1010         | method_call
1011         ;
1012
1013 /* lvalue - things you can assign to */
1014 lvalue
1015         : identifier
1016                 { $$.ident = newBuffer();
1017                   bufferWriteString($$.ident, $1, strlen($1)+1);
1018                   free($1);
1019                   $$.obj = 0;
1020                   $$.memexpr = 0; }
1021
1022         | lvalue_expr '.' identifier %prec '.'
1023                 { $$.obj = $1;
1024                   $$.ident = newBuffer();
1025                   bufferWriteString($$.ident, $3, strlen($3)+1);
1026                   $$.memexpr = 0; }
1027
1028         | lvalue_expr '[' expr ']' %prec '.'
1029                 { $$.obj = $1;
1030                   $$.memexpr = $3;
1031                   $$.ident = 0; }
1032         ;
1033
1034 /* these leave a value on the stack */
1035
1036 expr
1037         : primary
1038
1039         | '-' expr %prec UMINUS
1040                 { $$ = $2;
1041                   bufferWriteInt($2, -1);
1042                   bufferWriteOp($2, SWFACTION_MULTIPLY); }
1043
1044         | '~' expr %prec UMINUS
1045                 { $$ = $2;
1046                   bufferWriteInt($2, 0xffffffff);
1047                   bufferWriteOp($2, SWFACTION_BITWISEXOR); }
1048
1049         | '!' expr
1050                 { $$ = $2;
1051                   bufferWriteOp($2, SWFACTION_LOGICALNOT); }
1052
1053         | expr "||" expr
1054                 { $$ = $1;
1055                   bufferWriteOp($$, SWFACTION_DUP);
1056                   bufferWriteOp($$, SWFACTION_BRANCHIFTRUE);
1057                   bufferWriteS16($$, 2);
1058                   bufferWriteS16($$, bufferLength($3)+1);
1059                   bufferWriteOp($$, SWFACTION_POP);
1060                   bufferConcat($$, $3); }
1061
1062         | expr "&&" expr
1063                 { $$ = $1;
1064                   bufferWriteOp($$, SWFACTION_DUP);
1065                   bufferWriteOp($$, SWFACTION_LOGICALNOT);
1066                   bufferWriteOp($$, SWFACTION_BRANCHIFTRUE);
1067                   bufferWriteS16($$, 2);
1068                   bufferWriteS16($$, bufferLength($3)+1);
1069                   bufferWriteOp($$, SWFACTION_POP);
1070                   bufferConcat($$, $3); }
1071
1072         | expr '*' expr
1073                 { $$ = $1;
1074                   bufferConcat($$, $3);
1075                   bufferWriteOp($$, SWFACTION_MULTIPLY); }
1076
1077         | expr '/' expr
1078                 { $$ = $1;
1079                   bufferConcat($$, $3);
1080                   bufferWriteOp($$, SWFACTION_DIVIDE); }
1081
1082         | expr '%' expr
1083                 { $$ = $1;
1084                   bufferConcat($$, $3);
1085                   bufferWriteOp($$, SWFACTION_MODULO); }
1086
1087         | expr '+' expr
1088                 { $$ = $1;
1089                   bufferConcat($$, $3);
1090                   bufferWriteOp($$, SWFACTION_NEWADD); }
1091
1092         | expr '-' expr
1093                 { $$ = $1;
1094                   bufferConcat($$, $3);
1095                   bufferWriteOp($$, SWFACTION_SUBTRACT); }
1096
1097         | expr '&' expr
1098                 { $$ = $1;
1099                   bufferConcat($$, $3);
1100                   bufferWriteOp($$, SWFACTION_BITWISEAND); }
1101
1102         | expr '|' expr
1103                 { $$ = $1;
1104                   bufferConcat($$, $3);
1105                   bufferWriteOp($$, SWFACTION_BITWISEOR); }
1106
1107         | expr '^' expr
1108                 { $$ = $1;
1109                   bufferConcat($$, $3);
1110                   bufferWriteOp($$, SWFACTION_BITWISEXOR); }
1111
1112         | expr '<' expr
1113                 { $$ = $1;
1114                   bufferConcat($$, $3);
1115                   bufferWriteOp($$, SWFACTION_NEWLESSTHAN); }
1116
1117         | expr '>' expr
1118                 { $$ = $3;
1119                   bufferConcat($$, $1);
1120                   bufferWriteOp($$, SWFACTION_NEWLESSTHAN); }
1121
1122         | expr "<=" expr
1123                 { $$ = $3;
1124                   bufferConcat($$, $1);
1125                   bufferWriteOp($$, SWFACTION_NEWLESSTHAN);
1126                   bufferWriteOp($$, SWFACTION_LOGICALNOT); }
1127
1128         | expr ">=" expr
1129                 { bufferConcat($1, $3);
1130                   bufferWriteOp($1, SWFACTION_NEWLESSTHAN);
1131                   bufferWriteOp($1, SWFACTION_LOGICALNOT); }
1132
1133         | expr "==" expr
1134                 { bufferConcat($1, $3);
1135                   bufferWriteOp($1, SWFACTION_NEWEQUALS); }
1136
1137         | expr "!=" expr
1138                 { bufferConcat($1, $3);
1139                   bufferWriteOp($1, SWFACTION_NEWEQUALS);
1140                   bufferWriteOp($1, SWFACTION_LOGICALNOT); }
1141
1142         | expr "<<" expr
1143                 { bufferConcat($1, $3);
1144                   bufferWriteOp($1, SWFACTION_SHIFTLEFT); }
1145
1146         | expr ">>" expr
1147                 { bufferConcat($1, $3);
1148                   bufferWriteOp($1, SWFACTION_SHIFTRIGHT); }
1149
1150         | expr ">>>" expr
1151                 { bufferConcat($1, $3);
1152                   bufferWriteOp($1, SWFACTION_SHIFTRIGHT2); }
1153
1154         | expr '?' expr ':' expr
1155                 { bufferWriteOp($1, SWFACTION_BRANCHIFTRUE);
1156                   bufferWriteS16($1, 2);
1157                   bufferWriteS16($1, bufferLength($5)+5);
1158                   bufferConcat($1, $5);
1159                   bufferWriteOp($1, SWFACTION_BRANCHALWAYS);
1160                   bufferWriteS16($1, 2);
1161                   bufferWriteS16($1, bufferLength($3));
1162                   bufferConcat($1, $3); }
1163
1164         | lvalue '=' expr_or_obj
1165                 { if($1.obj) /* obj[memexpr] or obj.ident */
1166                   {
1167                     $$ = $1.obj;
1168
1169                     if($1.ident)
1170                       bufferConcat($$, $1.ident);
1171                     else
1172                       bufferConcat($$, $1.memexpr);
1173
1174                     bufferConcat($$, $3);
1175                     bufferWriteSetRegister($$, 0);
1176                     bufferWriteOp($$, SWFACTION_SETMEMBER);
1177                     bufferWriteRegister($$, 0);
1178                   }
1179                   else /* just ident */
1180                   {
1181                     $$ = $3;
1182                     bufferWriteOp($$, SWFACTION_DUP);
1183                     bufferConcat($$, $1.ident);
1184                     bufferWriteOp($$, SWFACTION_SWAP);
1185                     bufferWriteOp($$, SWFACTION_SETVARIABLE);
1186                   }
1187 /* tricky case missing here: lvalue ASSIGN expr */
1188 /* like in x = y += z; */
1189                 }
1190
1191         | expr INSTANCEOF lvalue_expr
1192                 { $$ = $1;
1193                   bufferConcat($$, $3);
1194                   bufferWriteOp($$, SWFACTION_INSTANCEOF); }
1195
1196         ;
1197
1198 expr_or_obj
1199         : expr
1200
1201         | NEW identifier
1202                 { $$ = newBuffer();
1203                   bufferWriteInt($$, 0);
1204                   bufferWriteString($$, $2, strlen($2)+1);
1205                   bufferWriteOp($$, SWFACTION_NEW); }
1206
1207         | NEW identifier '(' expr_list ')'
1208                 { $$ = $4.buffer;
1209                   bufferWriteInt($$, $4.count);
1210                   bufferWriteString($$, $2, strlen($2)+1);
1211                   bufferWriteOp($$, SWFACTION_NEW); }
1212
1213         | '[' expr_list ']'
1214                 { $$ = $2.buffer;
1215                   bufferWriteInt($$, $2.count);
1216                   bufferWriteOp($$, SWFACTION_INITARRAY); }
1217
1218         | emptybraces
1219                 { $$ = newBuffer();
1220                   bufferWriteInt($$, 0);
1221                   bufferWriteOp($$, SWFACTION_INITOBJECT); }
1222
1223         | '{' objexpr_list '}'
1224                 { $$ = $2.buffer;
1225                   bufferWriteInt($$, $2.count);
1226                   bufferWriteOp($$, SWFACTION_INITOBJECT); }
1227
1228         ;
1229
1230 primary
1231         : function_call
1232
1233         | anon_function_decl
1234
1235         | method_call
1236
1237         | lvalue_expr
1238
1239         | incdecop lvalue %prec "++"
1240                 { if($2.obj)
1241                   {
1242                     if($2.ident)        // expr . identifier
1243                     {
1244                       $$ = $2.obj;
1245                       bufferWriteOp($$, SWFACTION_DUP);       /* a, a */
1246                       bufferWriteBuffer($$, $2.ident);        /* a, a, i */
1247                       bufferWriteOp($$, SWFACTION_SWAP);      /* a, i, a */
1248                       bufferConcat($$, $2.ident);             /* a, i, a, i */
1249                       bufferWriteOp($$, SWFACTION_GETMEMBER);
1250                       bufferWriteOp($$, $1);
1251                       bufferWriteSetRegister($$, 0);
1252                       bufferWriteOp($$, SWFACTION_SETMEMBER); /* a.i = a.i+1 */
1253                       bufferWriteRegister($$, 0);             /* a.i+1 */
1254                     }
1255                     else        // expr [ expr ]
1256                     {
1257                       $$ = $2.memexpr;                        /* i */
1258                       bufferConcat($$, $2.obj);               /* i, a */
1259                       bufferWriteSetRegister($$, 0);    /* ($2.memexpr can use reg0) */
1260                       bufferWriteOp($$, SWFACTION_SWAP);      /* a, i */
1261                       bufferWriteOp($$, SWFACTION_DUP);       /* a, i, i */
1262                       bufferWriteRegister($$, 0);             /* a, i, i, a */
1263                       bufferWriteOp($$, SWFACTION_SWAP);      /* a, i, a, i */
1264                       bufferWriteOp($$, SWFACTION_GETMEMBER); /* a, i, a[i] */
1265                       bufferWriteOp($$, $1);                  /* a, i, a[i]+1 */
1266                       bufferWriteSetRegister($$, 0);
1267                       bufferWriteOp($$, SWFACTION_SETMEMBER); /* a[i] = a[i]+1 */
1268                       bufferWriteRegister($$, 0);             /* a[i]+1 */
1269                     }
1270                   }
1271                   else  // identifier
1272                   {
1273                     $$ = newBuffer();
1274                     bufferWriteBuffer($$, $2.ident);
1275                     bufferWriteOp($$, SWFACTION_GETVARIABLE);
1276                     bufferWriteOp($$, $1);
1277                     bufferWriteOp($$, SWFACTION_DUP);
1278                     bufferConcat($$, $2.ident);
1279                     bufferWriteOp($$, SWFACTION_SWAP);
1280                     bufferWriteOp($$, SWFACTION_SETVARIABLE);
1281                   }
1282                 }
1283
1284         | lvalue incdecop %prec POSTFIX
1285                 { if($1.obj)
1286                   {
1287                     if($1.ident)
1288                     {
1289                       $$ = $1.obj;                            /* a */
1290                       bufferWriteOp($$, SWFACTION_DUP);       /* a, a */
1291                       bufferWriteBuffer($$, $1.ident);        /* a, a, i */
1292                       bufferWriteOp($$, SWFACTION_GETMEMBER); /* a, a.i */
1293                       bufferWriteSetRegister($$, 0);
1294                       bufferWriteOp($$, SWFACTION_SWAP);      /* a.i, a */
1295                       bufferConcat($$, $1.ident);             /* a.i, a, i */
1296                       bufferWriteRegister($$, 0);             /* a.i, a, i, a.i */
1297                       bufferWriteOp($$, $2);                  /* a.i, a, i, a.i+1 */
1298                       bufferWriteOp($$, SWFACTION_SETMEMBER);
1299                     }
1300                     else
1301                     {
1302                       $$ = $1.memexpr;
1303                       bufferConcat($$, $1.obj);               /* i, a */
1304                       bufferWriteSetRegister($$, 0);
1305                       bufferWriteOp($$, SWFACTION_SWAP);      /* a, i */
1306                       bufferWriteOp($$, SWFACTION_DUP);       /* a, i, i */
1307                       bufferWriteRegister($$, 0);             /* a, i, i, a */
1308                       bufferWriteOp($$, SWFACTION_SWAP);      /* a, i, a, i */
1309                       bufferWriteOp($$, SWFACTION_GETMEMBER); /* a, i, a[i] */
1310                       bufferWriteSetRegister($$, 0);
1311                       bufferWriteOp($$, $2);                  /* a, i, a[i]+1 */
1312                       bufferWriteOp($$, SWFACTION_SETMEMBER);
1313                       bufferWriteRegister($$, 0);             /* a[i] */
1314                     }
1315                   }
1316                   else
1317                   {
1318                     $$ = newBuffer();
1319                     bufferWriteBuffer($$, $1.ident);
1320                     bufferWriteOp($$, SWFACTION_GETVARIABLE);
1321                     bufferWriteOp($$, SWFACTION_DUP);
1322                     bufferWriteOp($$, $2);
1323                     bufferConcat($$, $1.ident);
1324                     bufferWriteOp($$, SWFACTION_SWAP);
1325                     bufferWriteOp($$, SWFACTION_SETVARIABLE);
1326                   }
1327                 }
1328
1329         | '(' expr ')'
1330                 { $$ = $2; }
1331
1332         | '-' INTEGER %prec UMINUS
1333                 { $$ = newBuffer();
1334                   bufferWriteInt($$, -$2); }
1335
1336         | INTEGER
1337                 { $$ = newBuffer();
1338                   bufferWriteInt($$, $1); }
1339
1340         | '-' DOUBLE %prec UMINUS
1341                 { $$ = newBuffer();
1342                   bufferWriteDouble($$, -$2); }
1343
1344         | DOUBLE
1345                 { $$ = newBuffer();
1346                   bufferWriteDouble($$, $1); }
1347
1348         | BOOLEAN
1349                 { $$ = newBuffer();
1350                   bufferWriteBoolean($$, $1); }
1351
1352         | NULLVAL
1353                 { $$ = newBuffer();
1354                   bufferWriteNull($$); }
1355
1356         | STRING
1357                 { $$ = newBuffer();
1358                   bufferWriteString($$, $1, strlen($1)+1);
1359                   free($1); }
1360         ;
1361
1362 init_vars
1363         : init_var
1364
1365         | init_vars ',' init_var
1366                 { $$ = $1;
1367                   bufferConcat($$, $3); }
1368         ;
1369
1370 init_var
1371         : identifier '=' expr_or_obj
1372                 { $$ = newBuffer();
1373                   bufferWriteString($$, $1, strlen($1)+1);
1374                   bufferConcat($$, $3);
1375                   bufferWriteOp($$, SWFACTION_VAREQUALS); }
1376
1377         | identifier
1378                 { $$ = newBuffer();
1379                   bufferWriteString($$, $1, strlen($1)+1);
1380                   bufferWriteOp($$, SWFACTION_VAR); }
1381         ;
1382
1383 assign_stmt
1384         : ASM '{'
1385                 { asmBuffer = newBuffer(); }
1386           opcode_list '}'
1387                 { $$ = asmBuffer; }
1388
1389         | VAR init_vars
1390                 { $$ = $2; }
1391
1392         | void_function_call
1393
1394         | function_call
1395                 { $$ = $1;
1396                   bufferWriteOp($$, SWFACTION_POP); }
1397
1398         | method_call
1399                 { $$ = $1;
1400                   bufferWriteOp($$, SWFACTION_POP); }
1401
1402         | incdecop lvalue %prec INCR
1403                 { if($2.obj)
1404                   {
1405                     if($2.ident)
1406                     {
1407                       $$ = $2.obj;                            /* a */
1408                       bufferWriteOp($$, SWFACTION_DUP);       /* a, a */
1409                       bufferWriteBuffer($$, $2.ident);        /* a, a, i */
1410                       bufferWriteOp($$, SWFACTION_GETMEMBER); /* a, a.i */
1411                       bufferWriteOp($$, $1);                  /* a, a.i+1 */
1412                       bufferConcat($$, $2.ident);             /* a, a.i+1, i */
1413                       bufferWriteOp($$, SWFACTION_SWAP);      /* a, i, a.i+1 */
1414                       bufferWriteOp($$, SWFACTION_SETMEMBER); /* a.i = a.i+1 */
1415                     }
1416                     else
1417                     {
1418                       /* weird contortions so that $2.memexpr can use reg 0 */
1419                       $$ = $2.memexpr;                        /* i */
1420                       bufferConcat($$, $2.obj);               /* i, a */
1421                       bufferWriteSetRegister($$, 0);
1422                       bufferWriteOp($$, SWFACTION_SWAP);      /* a, i */
1423                       bufferWriteOp($$, SWFACTION_DUP);       /* a, i, i */
1424                       bufferWriteRegister($$, 0);             /* a, i, i, a */
1425                       bufferWriteOp($$, SWFACTION_SWAP);      /* a, i, a, i */
1426                       bufferWriteOp($$, SWFACTION_GETMEMBER); /* a, i, a[i] */
1427                       bufferWriteOp($$, $1);                  /* a, i, a[i]+1 */
1428                       bufferWriteOp($$, SWFACTION_SETMEMBER); /* a[i] = a[i]+1 */
1429                     }
1430                   }
1431                   else
1432                   {
1433                     $$ = $2.ident;
1434                     bufferWriteOp($$, SWFACTION_DUP);
1435                     bufferWriteOp($$, SWFACTION_GETVARIABLE);
1436                     bufferWriteOp($$, $1);
1437                     bufferWriteOp($$, SWFACTION_SETVARIABLE);
1438                   }
1439                 }
1440
1441         | lvalue incdecop %prec POSTFIX
1442                 { if($1.obj)
1443                   {
1444                     if($1.ident)
1445                     {
1446                       $$ = $1.obj;                            /* a */
1447                       bufferWriteOp($$, SWFACTION_DUP);       /* a, a */
1448                       bufferWriteBuffer($$, $1.ident);        /* a, a, i */
1449                       bufferWriteOp($$, SWFACTION_GETMEMBER); /* a, a.i */
1450                       bufferWriteOp($$, $2);                  /* a, a.i+1 */
1451                       bufferConcat($$, $1.ident);             /* a, a.i+1, i */
1452                       bufferWriteOp($$, SWFACTION_SWAP);      /* a, i, a.i+1 */
1453                       bufferWriteOp($$, SWFACTION_SETMEMBER); /* a.i = a.i+1 */
1454                     }
1455                     else
1456                     {
1457                       /* weird contortions so that $1.memexpr can use reg 0 */
1458                       $$ = $1.memexpr;  /* i */
1459                       bufferConcat($$, $1.obj);               /* i, a */
1460                       bufferWriteSetRegister($$, 0);
1461                       bufferWriteOp($$, SWFACTION_SWAP);      /* a, i */
1462                       bufferWriteOp($$, SWFACTION_DUP);       /* a, i, i */
1463                       bufferWriteRegister($$, 0);             /* a, i, i, a */
1464                       bufferWriteOp($$, SWFACTION_SWAP);      /* a, i, a, i */
1465                       bufferWriteOp($$, SWFACTION_GETMEMBER); /* a, i, a[i] */
1466                       bufferWriteOp($$, $2);                  /* a, i, a[i]+1 */
1467                       bufferWriteOp($$, SWFACTION_SETMEMBER); /* a[i] = a[i]+1 */
1468                     }
1469                   }
1470                   else
1471                   {
1472                     $$ = $1.ident;
1473                     bufferWriteOp($$, SWFACTION_DUP);   
1474                     bufferWriteOp($$, SWFACTION_GETVARIABLE);
1475                     bufferWriteOp($$, $2);
1476                     bufferWriteOp($$, SWFACTION_SETVARIABLE);
1477                   }
1478                 }
1479
1480         | lvalue '=' expr_or_obj
1481                 { if($1.obj)
1482                   {
1483                     $$ = $1.obj;
1484
1485                     if($1.ident)
1486                       bufferConcat($$, $1.ident);
1487                     else
1488                       bufferConcat($$, $1.memexpr);
1489
1490                     bufferConcat($$, $3);
1491                     bufferWriteOp($$, SWFACTION_SETMEMBER);
1492                   }
1493                   else
1494                   {
1495                     $$ = $1.ident;
1496                     bufferConcat($$, $3);
1497                     bufferWriteOp($$, SWFACTION_SETVARIABLE);
1498                   }
1499                 }
1500
1501         | lvalue assignop expr
1502                 { if($1.obj)
1503                   {
1504                     if($1.ident)
1505                     {
1506                       $$ = $1.obj;                            /* a */
1507                       bufferWriteOp($$, SWFACTION_DUP);       /* a, a */
1508                       bufferWriteBuffer($$, $1.ident);        /* a, a, i */
1509                       bufferWriteOp($$, SWFACTION_GETMEMBER); /* a, a.i */
1510                       bufferConcat($$, $3);                   /* a, a.i, v */
1511                       bufferWriteOp($$, $2);                  /* a, a.i+v */
1512                       bufferConcat($$, $1.ident);             /* a, a.i+v, i */
1513                       bufferWriteOp($$, SWFACTION_SWAP);      /* a, i, a.i+v */
1514                       bufferWriteOp($$, SWFACTION_SETMEMBER); /* a.i = a.i+v */
1515                     }
1516                     else
1517                     {
1518                       $$ = $1.memexpr;                        /* i */
1519                       bufferConcat($$, $1.obj);               /* i, a */
1520                       bufferWriteSetRegister($$, 0);
1521                       bufferWriteOp($$, SWFACTION_SWAP);      /* a, i */
1522                       bufferWriteOp($$, SWFACTION_DUP);       /* a, i, i */
1523                       bufferWriteRegister($$, 0);             /* a, i, i, a */
1524                       bufferWriteOp($$, SWFACTION_SWAP);      /* a, i, a, i */
1525                       bufferWriteOp($$, SWFACTION_GETMEMBER); /* a, i, a[i] */
1526                       bufferConcat($$, $3);                   /* a, i, a[i], v */
1527                       bufferWriteOp($$, $2);                  /* a, i, a[i]+v */
1528                       bufferWriteOp($$, SWFACTION_SETMEMBER); /* a[i] = a[i]+v */
1529                     }
1530                   }
1531                   else
1532                   {
1533                     $$ = $1.ident;
1534                     bufferWriteOp($$, SWFACTION_DUP);
1535                     bufferWriteOp($$, SWFACTION_GETVARIABLE);
1536                     bufferConcat($$, $3);
1537                     bufferWriteOp($$, $2);
1538                     bufferWriteOp($$, SWFACTION_SETVARIABLE);
1539                   }
1540                 }
1541         ;
1542
1543 /* assembler stuff */
1544
1545 opcode_list
1546         : opcode
1547         | opcode_list opcode    { $$ = $1 + $2; }
1548         ;
1549
1550 with
1551         : WITH
1552                                 { $$ = bufferWriteOp(asmBuffer,
1553                                                      SWFACTION_WITH); }
1554           opcode_list END       { $$ = $<len>2 + $3;
1555                                   bufferPatchLength(asmBuffer, $3); }
1556         ;
1557
1558 push_item
1559         : STRING                { $$ = bufferWriteConstantString(asmBuffer,(byte*) $1,
1560                                                                  strlen($1)+1); }
1561
1562         | INTEGER               { bufferWriteU8(asmBuffer, PUSH_INT);
1563                                   $$ = bufferWriteInt(asmBuffer, $1)+1; }
1564
1565         | DOUBLE                { bufferWriteU8(asmBuffer, PUSH_DOUBLE);
1566                                   $$ = bufferWriteDouble(asmBuffer, $1)+1; }
1567
1568         | BOOLEAN               { bufferWriteU8(asmBuffer, PUSH_BOOLEAN);
1569                                   $$ = bufferWriteU8(asmBuffer, $1)+1; }
1570
1571         | NULLVAL               { $$ = bufferWriteU8(asmBuffer, PUSH_NULL); }
1572
1573         | REGISTER              { bufferWriteU8(asmBuffer, PUSH_REGISTER);
1574                                   $$ = bufferWriteU8(asmBuffer,
1575                                                      (char)atoi($1))+1; }
1576         ;
1577
1578
1579 push_list
1580         : push_item                     { $$ = $1; }
1581         | push_list ',' push_item       { $$ += $3; }
1582         ;
1583
1584 opcode
1585         : PUSH                  { $$ = bufferWriteOp(asmBuffer,
1586                                                      SWFACTION_PUSHDATA);
1587                                   $$ += bufferWriteS16(asmBuffer, 0); }
1588           push_list             { $$ = $<len>2 + $3;
1589                                   bufferPatchLength(asmBuffer, $3); }
1590
1591         | with
1592
1593         | SETREGISTER REGISTER
1594                                 { $$ = bufferWriteOp(asmBuffer, 
1595                                                      SWFACTION_SETREGISTER);
1596                                   $$ += bufferWriteS16(asmBuffer, 1);
1597                                   $$ += bufferWriteU8(asmBuffer,
1598                                                       (char)atoi($2)); }
1599         /* no args */
1600         | CALLFUNCTION          { $$ = bufferWriteOp(asmBuffer,
1601                                                      SWFACTION_CALLFUNCTION); }
1602         | RETURN                { $$ = bufferWriteOp(asmBuffer,
1603                                                      SWFACTION_RETURN); }
1604         | CALLMETHOD    { $$ = bufferWriteOp(asmBuffer, 
1605                                                      SWFACTION_CALLMETHOD); }
1606         | AND                   { $$ = bufferWriteOp(asmBuffer, 
1607                                                      SWFACTION_BITWISEAND); }
1608         | OR                    { $$ = bufferWriteOp(asmBuffer, 
1609                                                      SWFACTION_BITWISEOR); }
1610         | XOR                   { $$ = bufferWriteOp(asmBuffer, 
1611                                                      SWFACTION_BITWISEXOR); }
1612         | MODULO                { $$ = bufferWriteOp(asmBuffer, 
1613                                                      SWFACTION_MODULO); }
1614         | ADD                   { $$ = bufferWriteOp(asmBuffer, 
1615                                                      SWFACTION_NEWADD); }
1616         | LESSTHAN              { $$ = bufferWriteOp(asmBuffer, 
1617                                                      SWFACTION_NEWLESSTHAN); }
1618         | EQUALS                { $$ = bufferWriteOp(asmBuffer, 
1619                                                      SWFACTION_NEWEQUALS); }
1620         | INC                   { $$ = bufferWriteOp(asmBuffer, 
1621                                                      SWFACTION_INCREMENT); }
1622         | DEC                   { $$ = bufferWriteOp(asmBuffer, 
1623                                                      SWFACTION_DECREMENT); }
1624         | TYPEOF                { $$ = bufferWriteOp(asmBuffer, 
1625                                                      SWFACTION_TYPEOF); }
1626         | INSTANCEOF    { $$ = bufferWriteOp(asmBuffer, 
1627                                                      SWFACTION_INSTANCEOF); }
1628         | ENUMERATE             { $$ = bufferWriteOp(asmBuffer, 
1629                                                      SWFACTION_ENUMERATE); }
1630         | DELETE                { $$ = bufferWriteOp(asmBuffer, 
1631                                                      SWFACTION_DELETE); }
1632         | NEW                   { $$ = bufferWriteOp(asmBuffer, 
1633                                                      SWFACTION_NEW); }
1634         | INITARRAY             { $$ = bufferWriteOp(asmBuffer, 
1635                                                      SWFACTION_INITARRAY); }
1636         | INITOBJECT            { $$ = bufferWriteOp(asmBuffer, 
1637                                                      SWFACTION_INITOBJECT); }
1638         | GETMEMBER             { $$ = bufferWriteOp(asmBuffer, 
1639                                                      SWFACTION_GETMEMBER); }
1640         | SETMEMBER             { $$ = bufferWriteOp(asmBuffer, 
1641                                                      SWFACTION_SETMEMBER); }
1642         | SHIFTLEFT             { $$ = bufferWriteOp(asmBuffer, 
1643                                                      SWFACTION_SHIFTLEFT); }
1644         | SHIFTRIGHT            { $$ = bufferWriteOp(asmBuffer, 
1645                                                      SWFACTION_SHIFTRIGHT); }
1646         | SHIFTRIGHT2           { $$ = bufferWriteOp(asmBuffer, 
1647                                                      SWFACTION_SHIFTRIGHT2); }
1648         | VAR                   { $$ = bufferWriteOp(asmBuffer, 
1649                                                      SWFACTION_VAR); }
1650         | VAREQUALS             { $$ = bufferWriteOp(asmBuffer, 
1651                                                      SWFACTION_VAREQUALS); }
1652
1653         /* f4 ops */
1654         | OLDADD                { $$ = bufferWriteOp(asmBuffer, SWFACTION_ADD); }
1655         | SUBTRACT              { $$ = bufferWriteOp(asmBuffer, SWFACTION_SUBTRACT); }
1656         | MULTIPLY              { $$ = bufferWriteOp(asmBuffer, SWFACTION_MULTIPLY); }
1657         | DIVIDE                { $$ = bufferWriteOp(asmBuffer, SWFACTION_DIVIDE); }
1658         | OLDEQUALS             { $$ = bufferWriteOp(asmBuffer, SWFACTION_EQUAL); }
1659         | OLDLESSTHAN           { $$ = bufferWriteOp(asmBuffer, SWFACTION_LESSTHAN); }
1660         | LOGICALAND            { $$ = bufferWriteOp(asmBuffer, SWFACTION_LOGICALAND); }
1661         | LOGICALOR             { $$ = bufferWriteOp(asmBuffer, SWFACTION_LOGICALOR); }
1662         | NOT                   { $$ = bufferWriteOp(asmBuffer, SWFACTION_LOGICALNOT); }
1663         | STRINGEQ              { $$ = bufferWriteOp(asmBuffer, SWFACTION_STRINGEQ); }
1664         | STRINGLENGTH          { $$ = bufferWriteOp(asmBuffer, SWFACTION_STRINGLENGTH); }
1665         | SUBSTRING             { $$ = bufferWriteOp(asmBuffer, SWFACTION_SUBSTRING); }
1666         | INT                   { $$ = bufferWriteOp(asmBuffer, SWFACTION_INT); }
1667         | DUP                   { $$ = bufferWriteOp(asmBuffer, SWFACTION_DUP); }
1668         | SWAP                  { $$ = bufferWriteOp(asmBuffer, SWFACTION_SWAP); }
1669         | POP                   { $$ = bufferWriteOp(asmBuffer, SWFACTION_POP); }
1670         | GETVARIABLE           { $$ = bufferWriteOp(asmBuffer, SWFACTION_GETVARIABLE); }
1671         | SETVARIABLE           { $$ = bufferWriteOp(asmBuffer, SWFACTION_SETVARIABLE); }
1672         | SETTARGETEXPRESSION   { $$ = bufferWriteOp(asmBuffer, SWFACTION_SETTARGETEXPRESSION); }
1673         | CONCAT                { $$ = bufferWriteOp(asmBuffer, SWFACTION_STRINGCONCAT); }
1674         | DUPLICATEMOVIECLIP    { $$ = bufferWriteOp(asmBuffer, SWFACTION_DUPLICATECLIP); }
1675         | REMOVEMOVIECLIP       { $$ = bufferWriteOp(asmBuffer, SWFACTION_REMOVECLIP); }
1676         | TRACE                 { $$ = bufferWriteOp(asmBuffer, SWFACTION_TRACE); }
1677         | STRINGLESSTHAN        { $$ = bufferWriteOp(asmBuffer, SWFACTION_STRINGCOMPARE); }
1678         | RANDOM                { $$ = bufferWriteOp(asmBuffer, SWFACTION_RANDOM); }
1679         | MBLENGTH              { $$ = bufferWriteOp(asmBuffer, SWFACTION_MBLENGTH); }
1680         | ORD                   { $$ = bufferWriteOp(asmBuffer, SWFACTION_ORD); }
1681         | CHR                   { $$ = bufferWriteOp(asmBuffer, SWFACTION_CHR); }
1682         | GETTIMER              { $$ = bufferWriteOp(asmBuffer, SWFACTION_GETTIMER); }
1683         | MBSUBSTRING           { $$ = bufferWriteOp(asmBuffer, SWFACTION_MBSUBSTRING); }
1684         | MBORD                 { $$ = bufferWriteOp(asmBuffer, SWFACTION_MBORD); }
1685         | MBCHR                 { $$ = bufferWriteOp(asmBuffer, SWFACTION_MBCHR); }
1686
1687         /* with args */
1688         | BRANCHALWAYS STRING   { $$ = bufferWriteOp(asmBuffer, SWFACTION_BRANCHALWAYS);
1689                                   $$ += bufferWriteS16(asmBuffer, 2);
1690                                   $$ += bufferBranchTarget(asmBuffer, $2); }
1691
1692         | BRANCHIFTRUE STRING   { $$ = bufferWriteOp(asmBuffer, SWFACTION_BRANCHIFTRUE);
1693                                   $$ += bufferWriteS16(asmBuffer, 2);
1694                                   $$ += bufferBranchTarget(asmBuffer, $2); }
1695         ;
1696
1697 %%
1698