wip
[henge/apc.git] / src / parser.y
1 /* Asset Package Compiler */
2 %code requires {
3 #include <unitypes.h>
4 }
5
6 %{
7 #include <stdio.h>
8 #include <string.h>
9 #include <dirent.h>
10 #include <unitypes.h>
11 #include "ir.h"
12
13 struct frame_spec_t { enum facing d; int w, h; };
14
15 extern long sys_pagesize;
16 extern int lexer();
17 static void yyerror(char const*);
18 /* Stack-based class handler */
19 static ir_class *class_stack, *csp;
20 static size_t class_stack_size;
21 static ir_class class_stack_init(void);
22 #define class_stack_pop() (*--csp)
23 static ir_class class_stack_push(ir_class);
24
25 #define yylex lexer
26 #define yyclass (*csp)
27 #define yyclassld (ir_classld_from_class(yyclass))
28 %}
29 %define parse.error verbose
30 %define lr.type ielr
31 %define api.pure full
32 %define api.push-pull push
33 %union {
34 long long ref;
35 int val;
36 enum facing face;
37 uint8_t* str;
38 ir_class class;
39 ir_set set;
40 ir_setld ld;
41 ir_setdata data;
42 struct frame_spec_t frame_spec;
43 }
44 /* Operators */
45 %token CLOPEN //(
46 %token CLCLOSE //)
47 %token MAP //~
48 %token AUDIO //AUDIO
49 %token SS //SS
50 %token LINK //#
51 /* Terminals */
52 %token <val> NUM
53 %token <str> PATH
54 %token <ref> REF
55 %token <face> FACING
56 %token <str> NAME
57 /* Types */
58 %type<data> data_spec
59 %type<set> set_spec
60 %type<ld> set_ld set_link
61 %type<frame_spec> frame_spec
62 /* Init */
63 %initial-action { class_stack_init(); }
64 %%
65 /* Syntax Directed Translation Scheme of the APC grammar */
66 progn:
67 class_list
68 | class_list statement_list
69 | statement_list
70 ;
71
72 class_list:
73 class_list class
74 | class
75 ;
76
77 class:
78 NAME CLOPEN { class_stack_push(ir_class_addchild(yyclass, $1)); }
79 progn
80 CLCLOSE { class_stack_pop(); }
81 ;
82
83 statement_list:
84 statement_list statement
85 | statement
86 ;
87
88 statement:
89 set_spec data_spec REF PATH { ir_data_assign_path($2,$4); ir_set_assign_data($1,$2); ir_set_assign_ref($1,$3); }
90 | set_spec data_spec PATH { ir_data_assign_path($2,$3); ir_set_assign_data($1,$2); }
91 | set_spec REF PATH { ir_set_assign_ref($1,$2); }
92 ;
93
94 data_spec:
95 SS NAME frame_spec { $$ = ir_framesheet($2,$3.d,$3.w,$3.h); }
96 | MAP NAME frame_spec { $$ = ir_mapsheet($2,$3.d,$3.w,$3.h); }
97 | AUDIO NAME { $$ = ir_audio($2); }
98 | LINK set_ld { $$ = ir_link_odat($2); }
99 | LINK set_ld MAP { $$ = ir_link_mdat($2,NULL); }
100 | LINK set_ld MAP NAME { $$ = ir_link_mdat($2,$4); }
101 | LINK set_ld SS { $$ = ir_link_vdat($2,NULL); }
102 | LINK set_ld SS NAME { $$ = ir_link_vdat($2,$4); }
103 | LINK set_ld AUDIO { $$ = ir_link_adat($2,NULL); }
104 | LINK set_ld AUDIO NAME { $$ = ir_link_adat($2,$4); }
105 ;
106
107 set_spec:
108 set_spec NAME { $$ = ir_set_addchild($1,$2); }
109 | NAME { $$ = ir_class_addset(yyclass,$1); }
110 ;
111
112 set_link:
113 set_link NAME { $$ = ir_setld_addchild($1,$2); }
114 | NAME { $$ = ir_setld_from_classld(yyclassld,$1) }
115 ;
116
117 set_ld:
118 set_link { $$ = $1; }
119 | REF { $$ = ir_setld_from_ref($1); }
120 ;
121
122 frame_spec:
123 NUM NUM { $$ = (struct frame_spec_t) {SFACE,$1,$2}; }
124 | FACING { $$ = (struct frame_spec_t) {$1,0,0}; }
125 | FACING NUM NUM { $$ = (struct frame_spec_t) {$1,$2,$3}; }
126 ;
127
128 %%
129
130 #define ERR_ALLOC "memory allocation error\n"
131
132 /* print to stderr */
133 static
134 void yyerror
135 ( char const *s )
136 { fprintf(stderr, "%s\n", s); }
137
138 /* Initialize the class stack
139 If the class_stack hasn't been allocated yet, allocates a page for pointers
140 to be stored in. Initializes class stack pointer, and inserts the root class
141 from IR
142 Returns the root class given by IR.
143 */
144 static
145 ir_class class_stack_init
146 ( void )
147 { if (class_stack == NULL)
148 { class_stack_size = (size_t) sys_pagesize;
149 class_stack = (ir_class*) malloc(class_stack_size);
150 if (class_stack == NULL)
151 { yyerror(ERR_MEM);
152 exit(1);
153 }
154 }
155 csp = class_stack;
156 return class_stack_push(ir_class_root());
157 }
158
159 /* Add a Class to the Stack
160 Allocated in page-sized chunks, potentially infinite depth is supported.
161 Returns the input class.
162 */
163 static
164 ir_class class_stack_push
165 #define class_size (sizeof(*class_stack))
166 ( ir_class class )
167 { size_t class_stack_len = csp - class_stack;
168 ir_class* new_class_stack;
169 if ((class_stack_len * class_size + class_size) > class_stack_size)
170 { class_stack_size += (size_t) sys_pagesize;
171 new_class_stack = (ir_class*) realloc(class_stack, class_stack_size);
172 if (new_class_stack == NULL)
173 { free(class_stack); //realloc failure does not free class_stack
174 yyerror("realloc " ERR_MEM);
175 exit(1);
176 }
177 class_stack = new_class_stack;
178 csp = class_stack + class_stack_len;
179 }
180 return (*csp++ = class);
181 }