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