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