/* Asset Package Compiler */ %code requires { #include typedef struct class_state_t yycstate; yycstate* yycstate_new(void); void yycstate_delete(yycstate*); } %{ #include #include #include #include #include "ir.h" struct class_state_t { ir_class *csp; size_t class_stack_size; ir_class *class_stack; }; struct frame_spec_t { enum facing d; int w, h; }; extern long sys_pagesize; extern int lexer(); static void yyerror(char const*); /* Stack-based class handler */ static ir_class class_stack_init(void); #define class_stack_pop() (*--csp) static ir_class class_stack_push(ir_class); #define yylex lexer #define yyclass (*csp) #define yyclassld (ir_classld_from_class(yyclass)) %} %define parse.error verbose %define lr.type ielr %define api.pure full %define api.push-pull push %parse-param {yycstate* cs} %union { long long ref; int val; enum facing face; uint8_t* str; ir_class class; ir_set set; ir_setld ld; ir_setdata data; struct frame_spec_t frame_spec; } /* Operators */ %token CLOPEN //( %token CLCLOSE //) %token MAP //~ %token AUDIO //AUDIO %token SS //SS %token LINK //# /* Terminals */ %token NUM %token PATH %token REF %token FACING %token NAME /* Types */ %type data_spec %type set_spec %type set_ld set_link %type frame_spec /* Init */ %initial-action { class_stack_init(); } %% /* Syntax Directed Translation Scheme of the APC grammar */ progn: class_list | class_list statement_list | statement_list ; class_list: class_list class | class ; class: NAME CLOPEN { class_stack_push(ir_class_addchild(yyclass, $1)); } progn CLCLOSE { class_stack_pop(); } ; statement_list: statement_list statement | statement ; statement: set_spec data_spec REF PATH { ir_data_assign_path($2,$4); ir_set_assign_data($1,$2); ir_set_assign_ref($1,$3); } | set_spec data_spec PATH { ir_data_assign_path($2,$3); ir_set_assign_data($1,$2); } | set_spec REF PATH { ir_set_assign_ref($1,$2); } ; data_spec: SS NAME frame_spec { $$ = ir_framesheet($2,$3.d,$3.w,$3.h); } | MAP NAME frame_spec { $$ = ir_mapsheet($2,$3.d,$3.w,$3.h); } | AUDIO NAME { $$ = ir_audio($2); } | LINK set_ld { $$ = ir_link_odat($2); } | LINK set_ld MAP { $$ = ir_link_mdat($2,NULL); } | LINK set_ld MAP NAME { $$ = ir_link_mdat($2,$4); } | LINK set_ld SS { $$ = ir_link_vdat($2,NULL); } | LINK set_ld SS NAME { $$ = ir_link_vdat($2,$4); } | LINK set_ld AUDIO { $$ = ir_link_adat($2,NULL); } | LINK set_ld AUDIO NAME { $$ = ir_link_adat($2,$4); } ; set_spec: set_spec NAME { $$ = ir_set_addchild($1,$2); } | NAME { $$ = ir_class_addset(yyclass,$1); } ; set_link: set_link NAME { $$ = ir_setld_addchild($1,$2); } | NAME { $$ = ir_setld_from_classld(yyclassld,$1) } ; set_ld: set_link { $$ = $1; } | REF { $$ = ir_setld_from_ref($1); } ; frame_spec: NUM NUM { $$ = (struct frame_spec_t) {SFACE,$1,$2}; } | FACING { $$ = (struct frame_spec_t) {$1,0,0}; } | FACING NUM NUM { $$ = (struct frame_spec_t) {$1,$2,$3}; } ; %% #define ERR_ALLOC "memory allocation error\n" /* print to stderr */ static void yyerror ( char const *s ) { fprintf(stderr, "%s\n", s); } /* Initialize the class stack If the class_stack hasn't been allocated yet, allocates a page for pointers to be stored in. Initializes class stack pointer, and inserts the root class from IR Returns the root class given by IR. */ static ir_class class_stack_init ( void ) { if (class_stack == NULL) { class_stack_size = (size_t) sys_pagesize; class_stack = (ir_class*) malloc(class_stack_size); if (class_stack == NULL) { yyerror(ERR_MEM); exit(1); } } csp = class_stack; return class_stack_push(ir_class_root()); } /* Add a Class to the Stack Allocated in page-sized chunks, potentially infinite depth is supported. Returns the input class. */ static ir_class class_stack_push #define class_size (sizeof(*class_stack)) ( ir_class class ) { size_t class_stack_len = csp - class_stack; ir_class* new_class_stack; if ((class_stack_len * class_size + class_size) > class_stack_size) { class_stack_size += (size_t) sys_pagesize; new_class_stack = (ir_class*) realloc(class_stack, class_stack_size); if (new_class_stack == NULL) { free(class_stack); //realloc failure does not free class_stack yyerror("realloc " ERR_MEM); exit(1); } class_stack = new_class_stack; csp = class_stack + class_stack_len; } return (*csp++ = class); } yycstate* yycstate_new ( void ) { yycstate* class_state; class_state = (yycstate*) malloc((size_t) sys_pagesize); if(class_state == NULL) { yyerror(ERR_MEM); exit(1); } class_state.class_stack = class_stack; class_state.csp = class_state.class_stack; class_state.class_stack_size = (size_t) sys_pagesize; class_stack_push(ir_class_root()); return class_state; } void yycstate_delete ( yycstate* class_state ) { free(class_state); }