initial checkin
[swftools.git] / lib / as3 / parser.y
1 //%glr-parser
2 //%expect-rr 1
3 %error-verbose
4
5 %token T_IDENTIFIER
6 %token T_STRING
7 %token T_REGEXP
8 %token T_DOTDOT ".."
9 %token T_COLONCOLON "::"
10 %token T_GE ">="
11 %token T_LE "<="
12 %token T_EQEQ "=="
13 %token T_PLUSPLUS "++"
14 %token T_MINUSMINUS "--"
15 %token T_IMPLEMENTS
16 %token T_NAMESPACE
17 %token T_PACKAGE
18 %token T_PROTECTED
19 %token T_PUBLIC
20 %token T_PRIVATE
21 %token T_UINT
22 %token T_USE
23 %token T_INTERNAL
24 %token T_INT
25 %token T_NEW
26 %token T_NATIVE
27 %token T_FUNCTION
28 %token T_FOR
29 %token T_CLASS
30 %token T_CONST
31 %token T_SET
32 %token T_STATIC
33 %token T_IMPORT
34 %token T_INTERFACE
35 %token T_NUMBER
36 %token T_NULL
37 %token T_FALSE
38 %token T_TRUE
39 %token T_BOOLEAN
40 %token T_VAR
41 %token T_AS
42 %token T_IS
43 %token T_DYNAMIC
44 %token T_OVERRIDE
45 %token T_FINAL
46 %token T_GET
47 %token T_EXTENDS
48
49
50 %token T_EMPTY
51      
52 %{
53 #include <stdlib.h>
54 #include <stdio.h>
55 #include <memory.h>
56 #include "abc.h"
57 #include "pool.h"
58 #include "files.h"
59 #include "tokenizer.h"
60 #include "registry.h"
61
62 static int yyerror(char*s)
63 {
64    syntaxerror("%s", s); 
65 }
66 static token_t* concat2(token_t* t1, token_t* t2)
67 {
68     NEW(token_t,t);
69     int l1 = strlen(t1->text);
70     int l2 = strlen(t2->text);
71     t->text = malloc(l1+l2+1);
72     memcpy(t->text   , t1->text, l1);
73     memcpy(t->text+l1, t2->text, l2);
74     t->text[l1+l2] = 0;
75     return t;
76 }
77 static token_t* concat3(token_t* t1, token_t* t2, token_t* t3)
78 {
79     NEW(token_t,t);
80     int l1 = strlen(t1->text);
81     int l2 = strlen(t2->text);
82     int l3 = strlen(t3->text);
83     t->text = malloc(l1+l2+l3+1);
84     memcpy(t->text   , t1->text, l1);
85     memcpy(t->text+l1, t2->text, l2);
86     memcpy(t->text+l1+l2, t3->text, l3);
87     t->text[l1+l2+l3] = 0;
88     return t;
89 }
90
91 typedef struct _import {
92     char*path;
93 } import_t;
94
95 DECLARE_LIST(import);
96
97 typedef struct _state {
98     abc_file_t*file;
99     abc_script_t*init;
100
101     int level;
102
103     char*package;     
104     char*function;
105     import_list_t*imports;
106    
107     /* class data */
108     char*classname;
109     abc_class_t*cls;
110
111 } state_t;
112
113 static state_t* state = 0;
114
115 DECLARE_LIST(state);
116
117 static state_list_t*state_stack=0;
118
119 static void initialize_state()
120 {
121     NEW(state_t, s);
122     NEW(state_list_t, sl);
123     state_stack = sl;
124     state = sl->state = s;
125
126     state->file = abc_file_new();
127     state->level = 0;
128     
129     state->init = abc_initscript(state->file, 0, 0);
130     abc_method_body_t*m = state->init->method->body;
131     __ getlocal_0(m);
132     __ pushscope(m);
133 }
134 static void finalize_state()
135 {
136     if(state->level) {
137         syntaxerror("unexpected end of file");
138     }
139     abc_method_body_t*m = state->init->method->body;
140     //__ popscope(m);
141     __ returnvoid(m);
142 }
143
144 static void new_state()
145 {
146     NEW(state_t, s);
147     NEW(state_list_t, sl);
148     memcpy(s, state, sizeof(state_t)); //shallow copy
149     sl->next = state_stack;
150     sl->state = s;
151     state_stack = sl;
152     state = s;
153     state->level++;
154 }
155 static void old_state()
156 {
157     if(!state_stack || !state_stack->next)
158         syntaxerror("invalid nesting");
159     state_t*oldstate = state;
160     state_list_t*old = state_stack;
161     state_stack = state_stack->next;
162     free(old);
163     state = state_stack->state;
164 }
165
166 static void startpackage(token_t*t) 
167 {
168     if(state->package) {
169         syntaxerror("Packages can not be nested."); 
170     } 
171     new_state();
172     char*name = t?t->text:"";
173     printf("entering package \"%s\"\n", name);
174     state->package = name;
175 }
176 static void endpackage()
177 {
178     printf("leaving package \"%s\"\n", state->package);
179     old_state();
180 }
181
182 static void startclass(token_t*modifiers, token_t*name, token_t*extends, token_t*implements)
183 {
184     token_list_t*t;
185     if(state->cls) {
186         syntaxerror("inner classes now allowed"); 
187     }
188     new_state();
189     state->classname = name->text;
190     printf("entering class %s\n", name->text);
191     printf("  modifiers: ");for(t=modifiers->tokens;t;t=t->next) printf("%s ", t->token->text);printf("\n");
192     printf("  extends: %s\n", extends->text);
193     printf("  implements (%d): ", list_length(implements->tokens));for(t=implements->tokens;t;t=t->next) printf("%s ", t->token->text);printf("\n");
194
195     char public=0,internal=0,final=0,sealed=1;
196     for(t=modifiers->tokens;t;t=t->next) {
197         if(t->token->type == T_INTERNAL) {
198             /* the programmer is being explicit- 
199                being internal is the default anyway */
200             internal = 1;
201         } else if(t->token->type == T_PUBLIC) {
202             public = 1;
203         } else if(t->token->type == T_FINAL) {
204             final = 1;
205         } else {
206             syntaxerror("modifier \"%s\" not supported in class declaration", t->token->text);
207         }
208     }
209     if(public&&internal)
210         syntaxerror("public and internal not supported at the same time.");
211
212     /* create the class name, together with the proper attributes */
213     multiname_t* classname = 0;
214     if(!public && !state->package)
215         classname = multiname_new(namespace_new_private(current_filename), state->classname);
216     else if(!public && state->package)
217         classname = multiname_new(namespace_new_packageinternal(state->package), state->classname);
218     else if(state->package)
219         classname = multiname_new(namespace_new_package(state->package), state->classname);
220     else
221         syntaxerror("public classes only allowed inside a package");
222
223     /* try to find the superclass */
224     multiname_t* superclass = 0;
225     if(extends->type != T_EMPTY) {
226         superclass = registry_findclass(extends->text);
227     } else {
228         superclass = registry_getobjectclass();
229     }
230
231     state->cls = abc_class_new(state->file, classname, superclass);
232     if(final) abc_class_final(state->cls);
233     if(sealed) abc_class_sealed(state->cls);
234
235     for(t=implements->tokens;t;t=t->next) {
236         abc_class_add_interface(state->cls, registry_findclass(t->token->text));
237     }
238
239     /* now write the construction code for this class */
240     int slotindex = abc_initscript_addClassTrait(state->init, classname, state->cls);
241
242     abc_method_body_t*m = state->init->method->body;
243     __ getglobalscope(m);
244     multiname_t*s = superclass;
245     int count=0;
246     while(s) {
247         //TODO: invert
248         //TODO: take a look at the current scope stack, maybe 
249         //      we can re-use something
250         __ getlex2(m, s);
251         __ pushscope(m);
252         s = registry_getsuperclass(s);
253         count++;
254     }
255     /* TODO: if this is one of *our* classes, we can also 
256              do a getglobalscope/getslot <nr> (which references
257              the init function's slots) */
258     __ getlex2(m, superclass);
259     __ newclass(m,state->cls);
260
261     while(count--) {
262         __ popscope(m);
263     }
264     __ setslot(m, slotindex);
265 }
266
267 static void endclass()
268 {
269     printf("leaving class %s\n", state->classname);
270     old_state();
271 }
272 static void addimport(token_t*t)
273 {
274     NEW(import_t,i);
275     i->path = t->text;
276     list_append(state->imports, i);
277 }
278 static void print_imports()
279 {
280     import_list_t*l = state->imports;
281     while(l) {
282         printf("  import %s\n", l->import->path);
283         l = l->next;
284     }
285 }
286 static void startfunction(token_t*ns, token_t*mod, token_t*getset, token_t*name,
287                           token_t*params, token_t*type)
288 {
289     token_list_t*t;
290     new_state();
291     state->function = name->text;
292     printf("entering function %s\n", name->text);
293     if(ns)
294         printf("  namespace: %s\n", ns->text);
295     printf("  getset: %s\n", getset->text);
296     printf("  params: ");for(t=params->tokens;t;t=t->next) printf("%s ", t->token->text);printf("\n");
297     printf("  mod: ");for(t=mod->tokens;t;t=t->next) printf("%s ", t->token->text);printf("\n");
298     printf("  type: %s\n", type->text);
299     print_imports();
300 }
301 static void endfunction()
302 {
303     printf("leaving function %s\n", state->function);
304     old_state();
305 }
306 static int newvariable(token_t*mod, token_t*varconst, token_t*name, token_t*type)
307 {
308     token_list_t*t;
309     printf("defining new variable %s\n", name->text);
310     printf("  mod: ");for(t=mod->tokens;t;t=t->next) printf("%s ", t->token->text);printf("\n");
311     printf("  access: ");printf("%s\n", varconst->text);
312     printf("  type: ");printf("%s\n", type->text);
313 }
314 static token_t* empty_token()
315 {
316     NEW(token_t,t);
317     t->type=T_EMPTY;
318     t->text=0;
319     return t;
320 }
321
322 void extend(token_t*list, token_t*add) {
323     list_append(list->tokens,add);
324     if(!list->text)
325         list->text = add->text;
326 }
327 void extend_s(token_t*list, char*seperator, token_t*add) {
328     list_append(list->tokens,add);
329     char*t1 = list->text;
330     char*t2 = seperator;
331     char*t3 = add->text;
332     int l1 = strlen(t1);
333     int l2 = strlen(t2);
334     int l3 = strlen(t3);
335     list->text = malloc(l1+l2+l3+1);
336     strcpy(list->text, t1);
337     strcpy(list->text+l1, t2);
338     strcpy(list->text+l1+l2, t3);
339     list->text[l1+l2+l3]=0;
340 }
341
342 %}
343 %%
344
345 PROGRAM: CODE PROGRAM
346 PROGRAM: 
347
348 //EMPTY: {
349 //    token_t* t = malloc(sizeof(token_t));
350 //    t->text = strdup("");
351 //    t->type = T_EMPTY;
352 //    $$ = t;
353 //}
354
355 CODE: CODE CODEPIECE {$$=$1;}
356 CODE: CODEPIECE {$$=empty_token();}
357
358 MAYBECODE: CODE
359 MAYBECODE: 
360
361 CODEPIECE: ';'
362 CODEPIECE: VARIABLE_DECLARATION {$$=$1;}
363 CODEPIECE: PACKAGE_DECLARATION
364 CODEPIECE: IMPORT
365 CODEPIECE: NAMESPACE_DECLARATION
366 CODEPIECE: CLASS_DECLARATION
367 CODEPIECE: INTERFACE_DECLARATION
368 CODEPIECE: FUNCTION_DECLARATION
369 CODEPIECE: EXPRESSION
370 CODEPIECE: FOR
371 CODEPIECE: USE
372 CODEPIECE: ASSIGNMENT
373
374 PACKAGE_DECLARATION : T_PACKAGE MULTILEVELIDENTIFIER '{' {startpackage($2)} MAYBECODE '}' {endpackage()}
375 PACKAGE_DECLARATION : T_PACKAGE '{' {startpackage(0)} MAYBECODE '}' {endpackage()}
376
377 IMPORT : T_IMPORT PACKAGESPEC {addimport($2);}
378
379 TYPE : BUILTIN_TYPE | '*' | T_IDENTIFIER
380 // TODO: do we need this? all it does it is clutter up our keyword space
381 BUILTIN_TYPE : T_STRING
382 BUILTIN_TYPE : T_NUMBER
383 BUILTIN_TYPE : T_INT
384 BUILTIN_TYPE : T_UINT
385 BUILTIN_TYPE : T_BOOLEAN
386 BUILTIN_TYPE : T_NULL
387
388 MAYBETYPE: ':' TYPE {$$=$2;}
389 MAYBETYPE:          {$$=empty_token();}
390
391 //FUNCTION_HEADER:      NAMESPACE MODIFIERS T_FUNCTION GETSET T_IDENTIFIER '(' PARAMS ')' 
392 FUNCTION_HEADER:      MODIFIERS T_FUNCTION GETSET T_IDENTIFIER '(' PARAMS ')' 
393                       MAYBETYPE
394 FUNCTION_DECLARATION: MODIFIERS T_FUNCTION GETSET T_IDENTIFIER '(' PARAMS ')' 
395                       MAYBETYPE '{' {startfunction(0,$1,$3,$4,$6,$8)} MAYBECODE '}' {endfunction()}
396
397 NAMESPACE_DECLARATION : MODIFIERS T_NAMESPACE T_IDENTIFIER
398 NAMESPACE_DECLARATION : MODIFIERS T_NAMESPACE T_IDENTIFIER '=' T_IDENTIFIER
399 NAMESPACE_DECLARATION : MODIFIERS T_NAMESPACE T_IDENTIFIER '=' T_STRING
400
401 //NAMESPACE :              {$$=empty_token();}
402 //NAMESPACE : T_IDENTIFIER {$$=$1};
403
404 CONSTANT : T_NUMBER
405 CONSTANT : T_STRING
406 CONSTANT : T_TRUE | T_FALSE
407 CONSTANT : T_NULL
408
409 VAR : T_CONST | T_VAR
410
411 // type annotation
412 // TODO: NAMESPACE
413
414 VARIABLE_DECLARATION : MODIFIERS VAR T_IDENTIFIER MAYBETYPE {
415     int i = newvariable($1,$2,$3,$4);
416 }
417 VARIABLE_DECLARATION : MODIFIERS VAR T_IDENTIFIER MAYBETYPE '=' EXPRESSION {
418     int i = newvariable($1,$2,$3,$4);
419     //setvariable(i,$6);
420 }
421
422 // operator prescendence:
423 // http://livedocs.adobe.com/flash/9.0/main/wwhelp/wwhimpl/common/html/wwhelp.htm?context=LiveDocs_Parts&file=00000012.html
424 EXPRESSION : EXPRESSION '<' EXPRESSION
425 EXPRESSION : EXPRESSION '>' EXPRESSION
426 EXPRESSION : EXPRESSION "<=" EXPRESSION
427 EXPRESSION : EXPRESSION ">=" EXPRESSION
428 EXPRESSION : EXPRESSION "==" EXPRESSION
429 EXPRESSION : EXPRESSION '+' TERM
430 EXPRESSION : EXPRESSION '-' TERM
431 EXPRESSION : TERM
432 EXPRESSION : '-' TERM
433 TERM : TERM '*' FACTOR
434 TERM : TERM '/' FACTOR
435 TERM : EMOD
436 EMOD: FACTOR "++"
437 EMOD: FACTOR "--"
438 EMOD: FACTOR
439 FACTOR : '(' EXPRESSION ')'
440 FACTOR : CONSTANT
441 FACTOR : VARIABLE
442 FACTOR : FUNCTIONCALL
443 FACTOR : T_REGEXP
444 FACTOR : NEW
445 FACTOR : IS
446 FACTOR : AS
447
448 IS : EXPRESSION T_IS TYPE
449 AS : EXPRESSION T_AS TYPE
450 NEW : T_NEW T_IDENTIFIER | T_NEW T_IDENTIFIER '(' ')'
451 NEW : T_NEW T_IDENTIFIER '(' EXPRESSIONLIST ')'
452
453 FUNCTIONCALL : VARIABLE '(' EXPRESSIONLIST ')'
454 FUNCTIONCALL : VARIABLE '(' ')'
455
456 EXPRESSIONLIST : EXPRESSION
457 EXPRESSIONLIST : EXPRESSION ',' EXPRESSIONLIST
458
459 VARIABLE : T_IDENTIFIER
460 VARIABLE : VARIABLE '.' T_IDENTIFIER
461 VARIABLE : VARIABLE ".." T_IDENTIFIER // descendants
462 VARIABLE : VARIABLE "::" VARIABLE // namespace declaration
463 VARIABLE : VARIABLE "::" '[' EXPRESSION ']' // qualified expression
464 VARIABLE : VARIABLE '[' EXPRESSION ']' // unqualified expression
465
466 ASSIGNMENT :           VARIABLE           '=' EXPRESSION
467 NEW_ASSIGNMENT : T_VAR VARIABLE MAYBETYPE '=' EXPRESSION
468
469 FOR : T_FOR '(' NEW_ASSIGNMENT ';' EXPRESSION ';' EXPRESSION ')' '{' MAYBECODE '}'
470 FOR : T_FOR '(' ASSIGNMENT     ';' EXPRESSION ';' EXPRESSION ')' '{' MAYBECODE '}'
471
472 USE : T_USE T_NAMESPACE T_IDENTIFIER
473
474 // keywords which also may be identifiers
475 X_IDENTIFIER : T_IDENTIFIER | T_PACKAGE
476
477 PACKAGESPEC : PACKAGESPEC '.' PACKAGESPEC {if($1->text[0]=='*') syntaxerror("wildcard in the middle of path");
478                                            $$ = concat3($1,$2,$3);}
479 PACKAGESPEC : X_IDENTIFIER                {$$=$1;}
480 PACKAGESPEC : '*'                         {$$=$1;}
481
482 GETSET : T_GET {$$=$1;}
483        | T_SET {$$=$1;}
484        |       {$$=empty_token();}
485
486 CLASS_DECLARATION : MODIFIERS T_CLASS T_IDENTIFIER EXTENDS IMPLEMENTS_LIST '{' {startclass($1,$3,$4,$5);} MAYBE_DECLARATION_LIST '}' {endclass();}
487 INTERFACE_DECLARATION : MODIFIERS T_INTERFACE T_IDENTIFIER EXTENDS_LIST '{' MAYBE_IDECLARATION_LIST '}'
488
489 PARAMS: {$$=empty_token();}
490 PARAMS: PARAM_LIST {$$=$1;}
491 PARAM_LIST: PARAM_LIST ',' PARAM {extend($1,$3);$$=$1;}
492 PARAM_LIST: PARAM                {$$=empty_token();extend($$,$1);}
493 PARAM:  T_IDENTIFIER ':' TYPE {$$=$1;}
494
495 MODIFIERS : {$$=empty_token();}
496 MODIFIERS : MODIFIER_LIST {$$=$1}
497 MODIFIER_LIST : MODIFIER MODIFIER_LIST {extend($2,$1);$$=$2;}
498 MODIFIER_LIST : MODIFIER               {$$=empty_token();extend($$,$1);}
499 MODIFIER : T_PUBLIC | T_PRIVATE | T_PROTECTED | T_STATIC | T_DYNAMIC | T_FINAL | T_OVERRIDE | T_NATIVE | T_INTERNAL
500
501 DECLARATION : VARIABLE_DECLARATION
502 DECLARATION : FUNCTION_DECLARATION
503
504 IDECLARATION : VARIABLE_DECLARATION
505 IDECLARATION : FUNCTION_DECLARATION
506
507 IMPLEMENTS_LIST : {$$=empty_token();}
508 IMPLEMENTS_LIST : T_IMPLEMENTS MIDENTIFIER_LIST {$$=$2;}
509
510 EXTENDS : {$$=empty_token();}
511 EXTENDS : T_EXTENDS MULTILEVELIDENTIFIER {$$=$2;}
512
513 EXTENDS_LIST : {$$=empty_token();}
514 EXTENDS_LIST : T_EXTENDS MIDENTIFIER_LIST {$$=$2;}
515
516 //IDENTIFIER_LIST : T_IDENTIFIER ',' IDENTIFIER_LIST {extend($3,$1);$$=$3;}
517 //IDENTIFIER_LIST : T_IDENTIFIER                     {$$=empty_token();extend($$,$1);}
518
519 MULTILEVELIDENTIFIER : T_IDENTIFIER                          {$$=empty_token();extend($$,$1);}
520 MULTILEVELIDENTIFIER : MULTILEVELIDENTIFIER '.' X_IDENTIFIER {extend_s($1,".",$3);$$=$1;}
521
522 MIDENTIFIER_LIST : MULTILEVELIDENTIFIER                      {$$=empty_token();extend($$,$1);}
523 MIDENTIFIER_LIST : MIDENTIFIER_LIST ',' MULTILEVELIDENTIFIER {extend($1,$3);$$=$1;}
524
525 MAYBE_DECLARATION_LIST : 
526 MAYBE_DECLARATION_LIST : DECLARATION_LIST
527 DECLARATION_LIST : DECLARATION
528 DECLARATION_LIST : DECLARATION_LIST DECLARATION
529
530 MAYBE_IDECLARATION_LIST : 
531 MAYBE_IDECLARATION_LIST : IDECLARATION_LIST
532 IDECLARATION_LIST : IDECLARATION
533 IDECLARATION_LIST : IDECLARATION_LIST FUNCTION_HEADER
534
535 // 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
536 // syntactic keywords: each get set namespace include dynamic final native override static
537 // chapter 14
538
539
540 %%
541
542 #ifdef MAIN
543
544 #include <stdlib.h>
545 #include <stdio.h>
546 #include <unistd.h>
547 #include <memory.h>
548
549 void test_lexer()
550 {
551     while(1) {
552         int token = yylex();
553         if(token==T_EOF)
554             break;
555         if(token>=32 && token<256) {
556             printf("'%c'\n", token);
557         } else {
558             printf("%s\n", token2string(avm2_lval));
559         }
560     }
561 }
562
563 int main(int argn, char*argv[])
564 {
565     //FILE*fi = fopen("/home/kramm/c/flex/text.as", "rb");
566     char*filename = "include.as";
567     char buf[512];
568     if(argn>1)
569         filename=argv[1];
570
571     add_include_dir(getcwd(buf, 512));
572     char*fullfilename = enter_file(filename, 0);
573
574     FILE*fi = fopen(fullfilename, "rb");
575     if(!fi) {
576         perror(fullfilename);
577         return 1;
578     }
579     initialize_state();
580     avm2_set_in(fi);
581
582     if(argn>2 && !strcmp(argv[2], "-lex")) {
583         test_lexer();
584         return 0;
585     }
586     avm2_parse();
587
588     finalize_state();
589
590     SWF swf;
591     memset(&swf, 0, sizeof(swf));
592     swf.fileVersion = 9;
593     swf.frameRate = 0x2500;
594     swf.movieSize.xmin = swf.movieSize.ymin = 0;
595     swf.movieSize.xmax = 1024*20;
596     swf.movieSize.ymax = 768*20;
597     TAG*tag = swf.firstTag = swf_InsertTag(0, ST_DOABC);
598     swf_WriteABC(tag, state->file);
599     swf_InsertTag(tag, ST_END);
600
601     int f = open("abc.swf",O_RDWR|O_CREAT|O_TRUNC|O_BINARY,0644);
602     swf_WriteSWF(f,&swf);
603     close(f);
604
605     return 0;
606 }
607 #endif