implemented if and else
[swftools.git] / lib / as3 / parser.y
1 /* parser.lex
2
3    Routines for compiling Flash2 AVM2 ABC Actionscript
4
5    Extension module for the rfxswf library.
6    Part of the swftools package.
7
8    Copyright (c) 2008 Matthias Kramm <kramm@quiss.org>
9  
10    This program is free software; you can redistribute it and/or modify
11    it under the terms of the GNU General Public License as published by
12    the Free Software Foundation; either version 2 of the License, or
13    (at your option) any later version.
14
15    This program is distributed in the hope that it will be useful,
16    but WITHOUT ANY WARRANTY; without even the implied warranty of
17    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18    GNU General Public License for more details.
19
20    You should have received a copy of the GNU General Public License
21    along with this program; if not, write to the Free Software
22    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */
23 %{
24 #include <stdlib.h>
25 #include <stdio.h>
26 #include <memory.h>
27 #include "abc.h"
28 #include "pool.h"
29 #include "files.h"
30 #include "tokenizer.h"
31 #include "registry.h"
32 #include "code.h"
33 #include "opcodes.h"
34 %}
35
36 //%glr-parser
37 //%expect-rr 1
38 %error-verbose
39
40 %union tokenunion {
41     tokenptr_t token;
42     multiname_t*multiname;
43     multiname_list_t*multiname_list;
44     int number_int;
45     unsigned int number_uint;
46     double number_float;
47     struct _code*code;
48     struct _code_list*code_list;
49     struct _writeable writeable;
50     char*string;
51 }
52
53
54 %token<token> T_IDENTIFIER
55 %token<string> T_STRING
56 %token<token> T_REGEXP
57 %token<token> T_EMPTY
58 %token<number_int> T_INT
59 %token<number_uint> T_UINT
60 %token<number_uint> T_BYTE
61 %token<number_uint> T_SHORT
62 %token<number_float> T_FLOAT
63
64 %token<token> KW_IMPLEMENTS
65 %token<token> KW_NAMESPACE
66 %token<token> KW_PACKAGE "package"
67 %token<token> KW_PROTECTED
68 %token<token> KW_PUBLIC
69 %token<token> KW_PRIVATE
70 %token<token> KW_USE "use"
71 %token<token> KW_INTERNAL
72 %token<token> KW_NEW "new"
73 %token<token> KW_NATIVE
74 %token<token> KW_FUNCTION "function"
75 %token<token> KW_FOR "for"
76 %token<token> KW_CLASS "class"
77 %token<token> KW_CONST "const"
78 %token<token> KW_SET "set"
79 %token<token> KW_STATIC
80 %token<token> KW_IMPORT "import"
81 %token<token> KW_INTERFACE "interface"
82 %token<token> KW_NULL
83 %token<token> KW_VAR "var"
84 %token<token> KW_DYNAMIC
85 %token<token> KW_OVERRIDE
86 %token<token> KW_FINAL
87 %token<token> KW_GET "get"
88 %token<token> KW_EXTENDS
89 %token<token> KW_FALSE "false"
90 %token<token> KW_TRUE "true"
91 %token<token> KW_BOOLEAN "Boolean"
92 %token<token> KW_UINT "uint"
93 %token<token> KW_INT "int"
94 %token<token> KW_NUMBER "Number"
95 %token<token> KW_STRING "String"
96 %token<token> KW_IF "if"
97 %token<token> KW_ELSE  "else"
98 %token<token> KW_IS "is"
99 %token<token> KW_AS "as"
100
101 %token<token> T_EQEQ "=="
102 %token<token> T_NE "!="
103 %token<token> T_LE "<="
104 %token<token> T_GE ">="
105 %token<token> T_DIVBY "/=" 
106 %token<token> T_MODBY "%="
107 %token<token> T_PLUSBY "+=" 
108 %token<token> T_MINUSBY "-="
109 %token<token> T_SHRBY ">>="
110 %token<token> T_SHLBY "<<="
111 %token<token> T_USHRBY ">>>="
112 %token<token> T_OROR "||"
113 %token<token> T_ANDAND "&&"
114 %token<token> T_COLONCOLON "::"
115 %token<token> T_MINUSMINUS "--"
116 %token<token> T_PLUSPLUS "++"
117 %token<token> T_DOTDOT ".."
118 %token<token> T_SHL "<<"
119 %token<token> T_USHR ">>>"
120 %token<token> T_SHR ">>"
121 %token<token> T_SEMICOLON ';'
122 %token<token> T_STAR '*'
123 %token<token> T_DOT '.'
124
125 %type <code> CODE
126 %type <code> CODEPIECE CODEPIECE2
127 %type <code> CODEBLOCK MAYBECODE
128 %type <token> PACKAGE_DECLARATION
129 %type <token> FUNCTION_DECLARATION
130 %type <code> VARIABLE_DECLARATION
131 %type <token> CLASS_DECLARATION
132 %type <token> NAMESPACE_DECLARATION
133 %type <token> INTERFACE_DECLARATION
134 %type <code> EXPRESSION
135 %type <code> MAYBEEXPRESSION
136 %type <code> E
137 %type <writeable> LH
138 %type <code> CONSTANT
139 %type <code> FOR IF MAYBEELSE
140 %type <token> USE
141 %type <code> ASSIGNMENT NEW_ASSIGNMENT SOME_ASSIGNMENT
142 %type <token> IMPORT
143 %type <multiname> MAYBETYPE
144 %type <token> PACKAGESPEC
145 %type <token> GETSET
146 %type <token> PARAM
147 %type <token> PARAMS
148 %type <token> PARAM_LIST
149 %type <token> MODIFIERS
150 %type <token> MODIFIER_LIST
151 %type <multiname_list> IMPLEMENTS_LIST
152 %type <multiname> EXTENDS
153 %type <multiname_list> EXTENDS_LIST
154 %type <multiname> PACKAGEANDCLASS
155 %type <multiname_list> PACKAGEANDCLASS_LIST
156 %type <token> MULTILEVELIDENTIFIER
157 %type <multiname> TYPE
158 %type <token> VAR
159 //%type <token> VARIABLE
160 %type <code> VAR_READ
161 %type <token> NEW
162 %type <token> X_IDENTIFIER
163 %type <token> MODIFIER
164 %type <token> PACKAGE
165 %type <code> FUNCTIONCALL
166 %type <code_list> MAYBE_EXPRESSION_LIST EXPRESSION_LIST
167
168 // precendence: from low to high
169 // http://livedocs.adobe.com/flash/9.0/main/wwhelp/wwhimpl/common/html/wwhelp.htm?context=LiveDocs_Parts&file=00000012.html
170
171 %left prec_none
172 %right '?' ':'
173 %nonassoc '='
174 %nonassoc "/=" "%="
175 %nonassoc "+=" "-="
176 %nonassoc ">>="
177 %nonassoc "<<="
178 %nonassoc ">>>="
179 %nonassoc "||"
180 %nonassoc "&&"
181 %nonassoc '|'
182 %nonassoc '^'
183 %nonassoc '&'
184 %nonassoc "!=" "==" "<=" '<' ">=" '>' // TODO: support "a < b < c" syntax?
185 %nonassoc "is"
186 %left '-'
187 %left '+'
188 %left "<<"
189 %left ">>>"
190 %left ">>"
191 %left '%'
192 %left '/'
193 %left '*'
194 %left '!'
195 %left '~'
196 %left "--" "++"
197 %left '['
198 %nonassoc "as"
199 %left '.' ".." "::"
200 %nonassoc T_IDENTIFIER
201 %left ';'
202 %nonassoc "else"
203 %left '('
204 %left prec_highest
205
206      
207 %{
208
209 static int yyerror(char*s)
210 {
211    syntaxerror("%s", s); 
212 }
213 static token_t* concat2(token_t* t1, token_t* t2)
214 {
215     NEW(token_t,t);
216     int l1 = strlen(t1->text);
217     int l2 = strlen(t2->text);
218     t->text = malloc(l1+l2+1);
219     memcpy(t->text   , t1->text, l1);
220     memcpy(t->text+l1, t2->text, l2);
221     t->text[l1+l2] = 0;
222     return t;
223 }
224 static token_t* concat3(token_t* t1, token_t* t2, token_t* t3)
225 {
226     NEW(token_t,t);
227     int l1 = strlen(t1->text);
228     int l2 = strlen(t2->text);
229     int l3 = strlen(t3->text);
230     t->text = malloc(l1+l2+l3+1);
231     memcpy(t->text   , t1->text, l1);
232     memcpy(t->text+l1, t2->text, l2);
233     memcpy(t->text+l1+l2, t3->text, l3);
234     t->text[l1+l2+l3] = 0;
235     return t;
236 }
237 static char* concat3str(const char* t1, const char* t2, const char* t3)
238 {
239     int l1 = strlen(t1);
240     int l2 = strlen(t2);
241     int l3 = strlen(t3);
242     char*text = malloc(l1+l2+l3+1);
243     memcpy(text   , t1, l1);
244     memcpy(text+l1, t2, l2);
245     memcpy(text+l1+l2, t3, l3);
246     text[l1+l2+l3] = 0;
247     return text;
248 }
249
250 typedef struct _import {
251     char*path;
252 } import_t;
253
254 DECLARE_LIST(import);
255
256 typedef struct _state {
257     abc_file_t*file;
258     abc_script_t*init;
259
260     int level;
261
262     char*package;     
263     char*function;
264     abc_method_body_t*m;
265     import_list_t*imports;
266    
267     /* class data */
268     char*classname;
269     abc_class_t*cls;
270
271     array_t*vars;
272
273 } state_t;
274
275 static state_t* state = 0;
276
277 DECLARE_LIST(state);
278
279 static state_list_t*state_stack=0;
280
281 void initialize_state()
282 {
283     NEW(state_t, s);
284     NEW(state_list_t, sl);
285     state_stack = sl;
286     state = sl->state = s;
287
288     state->file = abc_file_new();
289     state->file->flags &= ~ABCFILE_LAZY;
290     state->level = 0;
291     
292     state->init = abc_initscript(state->file, 0, 0);
293     abc_method_body_t*m = state->init->method->body;
294     __ getlocal_0(m);
295     __ pushscope(m);
296     __ findpropstrict(m, "[package]::trace");
297     __ pushstring(m, "[entering global init function]");
298     __ callpropvoid(m, "[package]::trace", 1);
299 }
300 void* finalize_state()
301 {
302     if(state->level) {
303         syntaxerror("unexpected end of file");
304     }
305     abc_method_body_t*m = state->init->method->body;
306     //__ popscope(m);
307     
308     __ findpropstrict(m, "[package]::trace");
309     __ pushstring(m, "[leaving global init function]");
310     __ callpropvoid(m, "[package]::trace", 1);
311     __ returnvoid(m);
312     return state->file;
313 }
314
315 static void new_state()
316 {
317     NEW(state_t, s);
318     NEW(state_list_t, sl);
319
320     if(state->m) {
321         syntaxerror("not able to start another method scope");
322     }
323
324     memcpy(s, state, sizeof(state_t)); //shallow copy
325     sl->next = state_stack;
326     sl->state = s;
327     state_stack = sl;
328     state = s;
329     state->level++;
330 }
331 static void old_state()
332 {
333     if(!state_stack || !state_stack->next)
334         syntaxerror("invalid nesting");
335     state_t*oldstate = state;
336     state_list_t*old = state_stack;
337     state_stack = state_stack->next;
338     free(old);
339     state = state_stack->state;
340 }
341
342 static void startpackage(token_t*t) 
343 {
344     if(state->package) {
345         syntaxerror("Packages can not be nested."); 
346     } 
347     new_state();
348     char*name = t?t->text:"";
349     printf("entering package \"%s\"\n", name);
350     state->package = name;
351 }
352 static void endpackage()
353 {
354     printf("leaving package \"%s\"\n", state->package);
355     old_state();
356 }
357
358 char*globalclass=0;
359 static void startclass(token_t*modifiers, token_t*name, multiname_t*extends, multiname_list_t*implements)
360 {
361     if(state->cls) {
362         syntaxerror("inner classes now allowed"); 
363     }
364     new_state();
365     state->classname = name->text;
366     printf("entering class %s\n", name->text);
367     token_list_t*t=0;
368     printf("  modifiers: ");for(t=modifiers->tokens;t;t=t->next) printf("%s ", t->token->text);printf("\n");
369     printf("  extends: %s\n", multiname_tostring(extends));
370
371     multiname_list_t*mlist=0;
372     printf("  implements (%d): ", list_length(implements));
373     for(mlist=implements;mlist;mlist=mlist->next)  {
374         printf("%s ", multiname_tostring(mlist->multiname));
375     }
376     printf("\n");
377
378     char public=0,internal=0,final=0,sealed=1;
379     for(t=modifiers->tokens;t;t=t->next) {
380         if(t->token->type == KW_INTERNAL) {
381             /* the programmer is being explicit- 
382                being internal is the default anyway */
383             internal = 1;
384         } else if(t->token->type == KW_PUBLIC) {
385             public = 1;
386         } else if(t->token->type == KW_FINAL) {
387             final = 1;
388         } else {
389             syntaxerror("modifier \"%s\" not supported in class declaration", t->token->text);
390         }
391     }
392     if(public&&internal)
393         syntaxerror("public and internal not supported at the same time.");
394
395     /* create the class name, together with the proper attributes */
396     multiname_t* classname = 0;
397     if(!public && !state->package)
398         classname = multiname_new(namespace_new_private(current_filename), state->classname);
399     else if(!public && state->package)
400         classname = multiname_new(namespace_new_packageinternal(state->package), state->classname);
401     else if(state->package)
402         classname = multiname_new(namespace_new_package(state->package), state->classname);
403     else
404         syntaxerror("public classes only allowed inside a package");
405
406     state->cls = abc_class_new(state->file, classname, extends);
407     if(final) abc_class_final(state->cls);
408     if(sealed) abc_class_sealed(state->cls);
409
410     for(mlist=implements;mlist;mlist=mlist->next) {
411         abc_class_add_interface(state->cls, mlist->multiname);
412     }
413
414     /* now write the construction code for this class */
415     int slotindex = abc_initscript_addClassTrait(state->init, classname, state->cls);
416
417     abc_method_body_t*m = state->init->method->body;
418     __ getglobalscope(m);
419     multiname_t*s = extends;
420
421     int count=0;
422     
423     while(s) {
424         //TODO: take a look at the current scope stack, maybe 
425         //      we can re-use something
426         s = registry_getsuperclass(s);
427         if(!s) 
428         break;
429         __ getlex2(m, s);
430         __ pushscope(m);
431         m->code = m->code->prev->prev; // invert
432         count++;
433     }
434     /* continue appending after last op end */
435     while(m->code && m->code->next) m->code = m->code->next; 
436
437     /* TODO: if this is one of *our* classes, we can also 
438              do a getglobalscope/getslot <nr> (which references
439              the init function's slots) */
440     __ getlex2(m, extends);
441     __ dup(m);
442     __ pushscope(m); // we get a Verify Error #1107 if this is not the top scope
443     __ newclass(m,state->cls);
444     while(count--) {
445         __ popscope(m);
446     }
447     __ setslot(m, slotindex);
448
449     if(!globalclass && public && multiname_equals(registry_getMovieClip(),extends)) {
450         if(state->package && state->package[0]) {
451             globalclass = concat3str(state->package, ".", state->classname);
452         } else {
453             globalclass = strdup(state->classname);
454         }
455     }
456 }
457
458 static void endclass()
459 {
460     printf("leaving class %s\n", state->classname);
461     old_state();
462 }
463 static void addimport(token_t*t)
464 {
465     NEW(import_t,i);
466     i->path = t->text;
467     list_append(state->imports, i);
468 }
469 static void print_imports()
470 {
471     import_list_t*l = state->imports;
472     while(l) {
473         printf("  import %s\n", l->import->path);
474         l = l->next;
475     }
476 }
477 static void startfunction(token_t*ns, token_t*mod, token_t*getset, token_t*name,
478                           token_t*params, multiname_t*type)
479 {
480     token_list_t*t;
481     new_state();
482     state->function = name->text;
483     printf("entering function %s\n", name->text);
484     if(ns)
485         printf("  namespace: %s\n", ns->text);
486     printf("  getset: %s\n", getset->text);
487     printf("  params: ");for(t=params->tokens;t;t=t->next) printf("%s ", t->token->text);printf("\n");
488     printf("  mod: ");for(t=mod->tokens;t;t=t->next) printf("%s ", t->token->text);printf("\n");
489     printf("  type: %s\n", multiname_tostring(type));
490     print_imports();
491
492     if(!strcmp(state->classname,name->text)) {
493         state->m = abc_class_constructor(state->cls, type, 0);
494     } else {
495         state->m = abc_class_method(state->cls, type, name->text, 0);
496     }
497     state->vars = array_new();
498     array_append(state->vars, "this", 0);
499
500     __ getlocal_0(state->m);
501     __ pushscope(state->m);
502 }
503 static void endfunction()
504 {
505     printf("leaving function %s\n", state->function);
506     __ returnvoid(state->m);
507
508     old_state();
509 }
510 static int newvariable(token_t*mod, token_t*varconst, token_t*name, multiname_t*type)
511 {
512     token_list_t*t;
513     printf("defining new variable %s\n", name->text);
514     if(mod) {
515         printf("  mod: ");for(t=mod->tokens;t;t=t->next) printf("%s ", t->token->text);printf("\n");
516     }
517     if(varconst) {
518         printf("  access: ");printf("%s\n", varconst->text);
519     }
520     printf("  type: ");printf("%s\n", multiname_tostring(type));
521
522     if(!state->vars) 
523         syntaxerror("not allowed to defined variables outside a method");
524
525     int index = array_find(state->vars, name->text);
526     if(index>=0) {
527         syntaxerror("Variable %s already defined", name->text);
528     } else {
529         index = array_append(state->vars, name->text, 0);
530     }
531     return index;
532 }
533 static token_t* empty_token()
534 {
535     NEW(token_t,t);
536     t->type=T_EMPTY;
537     t->text=0;
538     return t;
539 }
540
541 void extend(token_t*list, token_t*add) {
542     list_append(list->tokens,add);
543     if(!list->text)
544         list->text = add->text;
545 }
546 void extend_s(token_t*list, char*seperator, token_t*add) {
547     list_append(list->tokens,add);
548     char*t1 = list->text;
549     char*t2 = seperator;
550     char*t3 = add->text;
551     int l1 = strlen(t1);
552     int l2 = strlen(t2);
553     int l3 = strlen(t3);
554     list->text = malloc(l1+l2+l3+1);
555     strcpy(list->text, t1);
556     strcpy(list->text+l1, t2);
557     strcpy(list->text+l1+l2, t3);
558     list->text[l1+l2+l3]=0;
559 }
560
561 %}
562
563 %%
564
565 PROGRAM: MAYBECODE
566
567 MAYBECODE: CODE {$$=$1;}
568 MAYBECODE:      {$$=code_new();}
569
570 CODE: CODE CODEPIECE2 {$$=$1;}
571 CODE: CODEPIECE2 {$$=code_new();}
572
573 CODEPIECE2: CODEPIECE {
574     if(state->m) {
575         state->m->code = code_append(state->m->code, $1);
576     }
577 }
578
579 CODEPIECE: ';'                   {$$=code_new();}
580 CODEPIECE: VARIABLE_DECLARATION  {$$=$1}
581 CODEPIECE: PACKAGE_DECLARATION   {/*TODO*/$$=code_new();}
582 CODEPIECE: IMPORT                {/*TODO*/$$=code_new();}
583 CODEPIECE: NAMESPACE_DECLARATION {/*TODO*/$$=code_new();}
584 CODEPIECE: CLASS_DECLARATION     {/*TODO*/$$=code_new();}
585 CODEPIECE: INTERFACE_DECLARATION {/*TODO*/$$=code_new();}
586 CODEPIECE: FUNCTION_DECLARATION  {/*TODO*/$$=code_new();}
587 CODEPIECE: EXPRESSION            {/*calculate and discard*/$$=$1;$$=abc_pop($$);}
588 CODEPIECE: FOR                   {$$=$1}
589 CODEPIECE: IF                    {$$=$1}
590 CODEPIECE: USE                   {/*TODO*/$$=code_new();}
591 CODEPIECE: ASSIGNMENT            {/*TODO*/$$=code_new();}
592
593 CODEBLOCK :  '{' MAYBECODE '}' {$$=$2;}
594 CODEBLOCK :  CODEPIECE         {$$=$1;}
595
596 PACKAGE_DECLARATION : "package" MULTILEVELIDENTIFIER '{' {startpackage($2)} MAYBECODE '}' {endpackage()}
597 PACKAGE_DECLARATION : "package" '{' {startpackage(0)} MAYBECODE '}' {endpackage()}
598
599 IMPORT : "import" PACKAGESPEC {addimport($2);}
600
601 TYPE : PACKAGEANDCLASS {$$=$1;}
602      | '*'        {$$=registry_getanytype();}
603      |  "String"  {$$=registry_getstringclass();}
604      |  "int"     {$$=registry_getintclass();}
605      |  "uint"    {$$=registry_getuintclass();}
606      |  "Boolean" {$$=registry_getbooleanclass();}
607      |  "Number"  {$$=registry_getnumberclass();}
608
609 MAYBETYPE: ':' TYPE {$$=$2;}
610 MAYBETYPE:          {$$=0;}
611
612 //FUNCTION_HEADER:      NAMESPACE MODIFIERS T_FUNCTION GETSET T_IDENTIFIER '(' PARAMS ')' 
613 FUNCTION_HEADER:      MODIFIERS "function" GETSET T_IDENTIFIER '(' PARAMS ')' 
614                       MAYBETYPE
615 FUNCTION_DECLARATION: MODIFIERS "function" GETSET T_IDENTIFIER '(' PARAMS ')' 
616                       MAYBETYPE '{' {startfunction(0,$1,$3,$4,$6,$8)} MAYBECODE '}' {endfunction()}
617
618 NAMESPACE_DECLARATION : MODIFIERS KW_NAMESPACE T_IDENTIFIER
619 NAMESPACE_DECLARATION : MODIFIERS KW_NAMESPACE T_IDENTIFIER '=' T_IDENTIFIER
620 NAMESPACE_DECLARATION : MODIFIERS KW_NAMESPACE T_IDENTIFIER '=' T_STRING
621
622 //NAMESPACE :              {$$=empty_token();}
623 //NAMESPACE : T_IDENTIFIER {$$=$1};
624
625 CONSTANT : T_BYTE {$$ = abc_pushbyte(0, $1);$$=abc_coerce2($$,registry_getnumberclass());}
626 CONSTANT : T_SHORT {$$ = abc_pushshort(0, $1);}
627 CONSTANT : T_INT {$$ = abc_pushint(0, $1);}
628 CONSTANT : T_UINT {$$ = abc_pushuint(0, $1);}
629 CONSTANT : T_FLOAT {$$ = abc_pushdouble(0, $1);}
630 CONSTANT : T_STRING {$$ = abc_pushstring(0, $1);}
631 CONSTANT : KW_TRUE {$$ = abc_pushtrue(0);}
632 CONSTANT : KW_FALSE {$$ = abc_pushfalse(0);}
633 CONSTANT : KW_NULL {$$ = abc_pushnull(0);}
634
635 VAR : "const" | "var"
636
637 // type annotation
638 // TODO: NAMESPACE
639
640 VARIABLE_DECLARATION : MODIFIERS VAR T_IDENTIFIER MAYBETYPE MAYBEEXPRESSION {
641     int i = newvariable($1,$2,$3,$4);
642     $$ = $5;
643     $$ = abc_setlocal($$, i);
644 }
645
646 NEW_ASSIGNMENT : "var" T_IDENTIFIER MAYBETYPE '=' EXPRESSION {
647     int i = newvariable(0,0,$2,$3);
648     $$ = $5;
649     $$ = abc_setlocal($$, i);
650 }
651 ASSIGNMENT :           T_IDENTIFIER '=' EXPRESSION {
652     int i = array_find(state->vars, $1->text);
653     if(i<0) {
654         syntaxerror("Unknown variable '%s'", $1->text);
655     } 
656     $$ = $3;
657     $$ = abc_setlocal($$, i);
658 }
659 SOME_ASSIGNMENT : ASSIGNMENT | NEW_ASSIGNMENT
660
661 FOR : "for" '(' SOME_ASSIGNMENT ';' EXPRESSION ';' EXPRESSION ')' '{' MAYBECODE '}' {
662     $$ = $3;
663     code_t*loopstart = $$ = abc_label($$);
664     $$ = code_append($$, $5);
665     code_t*myif = $$ = abc_iffalse($$, 0);
666     $$ = code_append($$, $10);
667     $$ = code_append($$, $7);$$=abc_pop($$);
668     $$ = abc_jump($$, loopstart);
669     $$ = abc_label($$);
670     myif->branch = $$;
671 }
672 MAYBEELSE:  %prec prec_none {$$ = code_new();}
673 MAYBEELSE: "else" CODEBLOCK {$$=$2;}
674 MAYBEELSE: ';' "else" CODEBLOCK {$$=$3;}
675
676 IF  : "if" '(' EXPRESSION ')' CODEBLOCK MAYBEELSE {
677     $$=$3;
678     code_t*myjmp,*myif = $$ = abc_iffalse($$, 0);
679     $$ = code_append($$, $5);
680     if($6) {
681         myjmp = $$ = abc_jump($$, 0);
682     }
683     myif->branch = $$ = abc_label($$);
684     if($6) {
685         $$ = code_append($$, $6);
686         myjmp->branch = $$ = abc_label($$);
687     }
688 }
689
690 USE : "use" KW_NAMESPACE T_IDENTIFIER
691
692
693 MAYBEEXPRESSION : '=' EXPRESSION {$$=$2;}
694                 |                {$$=code_new();}
695
696 EXPRESSION : E %prec prec_none  /*precendence below '-x'*/ {$$ = $1;}
697
698 E : CONSTANT
699 E : VAR_READ %prec T_IDENTIFIER {$$ = $1;}
700 E : NEW                         {$$ = abc_pushundefined(0); /* FIXME */}
701 E : T_REGEXP                    {$$ = abc_pushundefined(0); /* FIXME */}
702 E : FUNCTIONCALL
703 E : E '<' E {$$ = code_append($1,$3);$$ = abc_greaterequals($$);$$=abc_not($$);}
704 E : E '>' E {$$ = code_append($1,$3);$$ = abc_greaterthan($$);}
705 E : E "<=" E {$$ = code_append($1,$3);$$ = abc_greaterthan($$);$$=abc_not($$);}
706 E : E ">=" E {$$ = code_append($1,$3);$$ = abc_greaterequals($$);}
707 E : E "==" E {$$ = code_append($1,$3);$$ = abc_equals($$);}
708 E : E "!=" E {$$ = code_append($1,$3);$$ = abc_equals($$);$$ = abc_not($$);}
709 E : E '+' E  {$$ = code_append($1,$3);$$ = abc_add($$);}
710 E : E '-' E
711 E : E '/' E
712 E : E '%' E
713 E : E '*' E
714 E : E "as" TYPE
715 E : E "is" TYPE
716 E : '(' E ')' {$$=$2;}
717 E : '-' E {$$=$2;}
718
719 // TODO: use inclocal where appropriate
720 E : LH "++" {$$ = $1.read;$$=abc_increment($$);$$=abc_dup($$);$$=code_append($$,$1.write);}
721 E : LH "--" {$$ = $1.read;$$=abc_decrement($$);$$=abc_dup($$);$$=code_append($$,$1.write);}
722
723 LH: T_IDENTIFIER {
724   int i = array_find(state->vars, $1->text);
725   if(i<0) syntaxerror("unknown variable '%s'", $1->text);
726   $$.read = abc_getlocal(0, i);
727   $$.write = abc_setlocal(0, i);
728 }
729
730 NEW : "new" T_IDENTIFIER
731     | "new" T_IDENTIFIER '(' ')'
732     | "new" T_IDENTIFIER '(' EXPRESSION_LIST ')'
733
734 FUNCTIONCALL : T_IDENTIFIER '(' MAYBE_EXPRESSION_LIST ')' {
735         /* TODO: use abc_call (for calling local variables),
736                  abc_callstatic (for calling own methods) */
737         $$ = code_new();
738         $$ = abc_findproperty($$, $1->text);
739         code_list_t*l = $3;
740         // push parameters on stack
741         while(l) {
742             $$ = code_append($$, l->code);
743             l = l->next;
744         }
745         $$ = abc_callproperty($$, $1->text, list_length($3));
746 }
747
748 MAYBE_EXPRESSION_LIST : {}
749 MAYBE_EXPRESSION_LIST : EXPRESSION_LIST
750 EXPRESSION_LIST : EXPRESSION                     {$$=list_new();list_append($$,$1);}
751 EXPRESSION_LIST : EXPRESSION_LIST ',' EXPRESSION {list_append($$,$3);}
752
753 VAR_READ : T_IDENTIFIER {
754         int i = array_find(state->vars, $1->text);
755         if(i<0)
756             syntaxerror("unknown variable '%s'", $1->text);
757         $$ = abc_getlocal(0, i);
758 }
759
760 //VARIABLE : T_IDENTIFIER
761 //VARIABLE : VARIABLE '.' T_IDENTIFIER
762 //VARIABLE : VARIABLE ".." T_IDENTIFIER // descendants
763 //VARIABLE : VARIABLE "::" VARIABLE // namespace declaration
764 //VARIABLE : VARIABLE "::" '[' EXPRESSION ']' // qualified expression
765 //VARIABLE : VARIABLE '[' EXPRESSION ']' // unqualified expression
766
767 // keywords which also may be identifiers
768 X_IDENTIFIER : T_IDENTIFIER | KW_PACKAGE
769
770 PACKAGESPEC : PACKAGESPEC '.' PACKAGESPEC {if($1->text[0]=='*') syntaxerror("wildcard in the middle of path");
771                                            $$ = concat3($1,$2,$3);}
772 PACKAGESPEC : X_IDENTIFIER                {$$=$1;}
773 PACKAGESPEC : '*'                         {$$=$1;}
774
775 GETSET : "get" {$$=$1;}
776        | "set" {$$=$1;}
777        |       {$$=empty_token();}
778
779 CLASS_DECLARATION : MODIFIERS "class" T_IDENTIFIER EXTENDS IMPLEMENTS_LIST '{' {startclass($1,$3,$4,$5);} MAYBE_DECLARATION_LIST '}' {endclass();}
780 INTERFACE_DECLARATION : MODIFIERS "interface" T_IDENTIFIER EXTENDS_LIST '{' MAYBE_IDECLARATION_LIST '}'
781
782 PARAMS: {$$=empty_token();}
783 PARAMS: PARAM_LIST {$$=$1;}
784 PARAM_LIST: PARAM_LIST ',' PARAM {extend($1,$3);$$=$1;}
785 PARAM_LIST: PARAM                {$$=empty_token();extend($$,$1);}
786 PARAM:  T_IDENTIFIER ':' TYPE {$$=$1;}
787
788 MODIFIERS : {$$=empty_token();}
789 MODIFIERS : MODIFIER_LIST {$$=$1}
790 MODIFIER_LIST : MODIFIER MODIFIER_LIST {extend($2,$1);$$=$2;}
791 MODIFIER_LIST : MODIFIER               {$$=empty_token();extend($$,$1);}
792 MODIFIER : KW_PUBLIC | KW_PRIVATE | KW_PROTECTED | KW_STATIC | KW_DYNAMIC | KW_FINAL | KW_OVERRIDE | KW_NATIVE | KW_INTERNAL
793
794 DECLARATION : VARIABLE_DECLARATION
795 DECLARATION : FUNCTION_DECLARATION
796
797 IDECLARATION : VARIABLE_DECLARATION
798 IDECLARATION : FUNCTION_DECLARATION
799
800 IMPLEMENTS_LIST : {$$=list_new();}
801 IMPLEMENTS_LIST : KW_IMPLEMENTS PACKAGEANDCLASS_LIST {$$=$2;}
802
803 EXTENDS : {$$=registry_getobjectclass();}
804 EXTENDS : KW_EXTENDS PACKAGEANDCLASS {$$=$2;}
805
806 EXTENDS_LIST : {$$=list_new();}
807 EXTENDS_LIST : KW_EXTENDS PACKAGEANDCLASS_LIST {$$=$2;}
808
809 //IDENTIFIER_LIST : T_IDENTIFIER ',' IDENTIFIER_LIST {extend($3,$1);$$=$3;}
810 //IDENTIFIER_LIST : T_IDENTIFIER                     {$$=empty_token();extend($$,$1);}
811
812 PACKAGEANDCLASS : T_IDENTIFIER {$$ = registry_findclass(state->package, $1->text);}
813 PACKAGEANDCLASS : PACKAGE '.' T_IDENTIFIER {$$ = registry_findclass($1->text, $3->text);}
814 PACKAGE : X_IDENTIFIER
815 PACKAGE : PACKAGE '.' X_IDENTIFIER {$$=$1;extend_s($$,".",$3);}
816
817 MULTILEVELIDENTIFIER : MULTILEVELIDENTIFIER '.' X_IDENTIFIER {$$=$1;extend_s($$, ".", $3)}
818 MULTILEVELIDENTIFIER : T_IDENTIFIER                 {$$=$1;extend($$,$1)};
819
820 PACKAGEANDCLASS_LIST : PACKAGEANDCLASS {$$=list_new();list_append($$, $1);}
821 PACKAGEANDCLASS_LIST : PACKAGEANDCLASS_LIST ',' PACKAGEANDCLASS {$$=$1;list_append($$,$3);}
822
823 MAYBE_DECLARATION_LIST : 
824 MAYBE_DECLARATION_LIST : DECLARATION_LIST
825 DECLARATION_LIST : DECLARATION
826 DECLARATION_LIST : DECLARATION_LIST DECLARATION
827
828 MAYBE_IDECLARATION_LIST : 
829 MAYBE_IDECLARATION_LIST : IDECLARATION_LIST
830 IDECLARATION_LIST : IDECLARATION
831 IDECLARATION_LIST : IDECLARATION_LIST FUNCTION_HEADER
832
833 // chapter 14
834 // keywords: as break case catch class const continue default delete do else extends false finally for function if implements import in instanceof interface internal is native new null package private protected public return super switch this throw to true try typeof use var void while with
835 // syntactic keywords: each get set namespace include dynamic final native override static
836