Initial import from FreeBSD RELENG_4:
[dragonfly.git] / games / atc / grammar.y
1 /*-
2  * Copyright (c) 1990, 1993
3  *      The Regents of the University of California.  All rights reserved.
4  *
5  * This code is derived from software contributed to Berkeley by
6  * Ed James.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
11  * 1. Redistributions of source code must retain the above copyright
12  *    notice, this list of conditions and the following disclaimer.
13  * 2. Redistributions in binary form must reproduce the above copyright
14  *    notice, this list of conditions and the following disclaimer in the
15  *    documentation and/or other materials provided with the distribution.
16  * 3. All advertising materials mentioning features or use of this software
17  *    must display the following acknowledgement:
18  *      This product includes software developed by the University of
19  *      California, Berkeley and its contributors.
20  * 4. Neither the name of the University nor the names of its contributors
21  *    may be used to endorse or promote products derived from this software
22  *    without specific prior written permission.
23  *
24  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
25  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
26  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
27  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
28  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
29  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
30  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
31  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
32  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
33  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
34  * SUCH DAMAGE.
35  */
36
37 /*
38  * Copyright (c) 1987 by Ed James, UC Berkeley.  All rights reserved.
39  *
40  * Copy permission is hereby granted provided that this notice is
41  * retained on all partial or complete copies.
42  *
43  * For more info on this and all of my stuff, mail edjames@berkeley.edu.
44  */
45
46 %token <ival>   HeightOp
47 %token <ival>   WidthOp
48 %token <ival>   UpdateOp
49 %token <ival>   NewplaneOp
50 %token <cval>   DirOp
51 %token <ival>   ConstOp
52 %token <ival>   LineOp
53 %token <ival>   AirportOp
54 %token <ival>   BeaconOp
55 %token <ival>   ExitOp
56 %union {
57         int     ival;
58         char    cval;
59 }
60
61 %{
62 #include "include.h"
63
64 #ifndef lint
65 static char sccsid[] = "@(#)grammar.y   8.1 (Berkeley) 5/31/93";
66 #endif /* not lint */
67
68 int     errors = 0;
69 int     line = 1;
70 %}
71
72 %%
73 file:
74         bunch_of_defs { if (checkdefs() < 0) return (errors); } bunch_of_lines
75                 { 
76                 if (sp->num_exits + sp->num_airports < 2)
77                         yyerror("Need at least 2 airports and/or exits.");
78                 return (errors);
79                 }
80         ;
81
82 bunch_of_defs:
83         def bunch_of_defs
84         | def
85         ;
86
87 def:
88         udef
89         | ndef
90         | wdef
91         | hdef
92         ;
93
94 udef:
95         UpdateOp '=' ConstOp ';'
96                 {
97                 if (sp->update_secs != 0)
98                         return (yyerror("Redefinition of 'update'."));
99                 else if ($3 < 1)
100                         return (yyerror("'update' is too small."));
101                 else
102                         sp->update_secs = $3;
103                 }
104         ;
105
106 ndef:
107         NewplaneOp '=' ConstOp ';'
108                 {
109                 if (sp->newplane_time != 0)
110                         return (yyerror("Redefinition of 'newplane'."));
111                 else if ($3 < 1)
112                         return (yyerror("'newplane' is too small."));
113                 else
114                         sp->newplane_time = $3;
115                 }
116         ;
117
118 hdef:
119         HeightOp '=' ConstOp ';'
120                 {
121                 if (sp->height != 0)
122                         return (yyerror("Redefinition of 'height'."));
123                 else if ($3 < 3)
124                         return (yyerror("'height' is too small."));
125                 else
126                         sp->height = $3; 
127                 }
128         ;
129
130 wdef:
131         WidthOp '=' ConstOp ';'
132                 {
133                 if (sp->height != 0)
134                         return (yyerror("Redefinition of 'width'."));
135                 else if ($3 < 3)
136                         return (yyerror("'width' is too small."));
137                 else
138                         sp->width = $3; 
139                 }
140         ;
141
142 bunch_of_lines:
143         line bunch_of_lines
144                 {}
145         | line
146                 {}
147         ;
148
149 line:
150         BeaconOp ':' Bpoint_list ';'
151                 {}
152         | ExitOp ':' Epoint_list ';'
153                 {}
154         | LineOp ':' Lline_list ';'
155                 {}
156         | AirportOp ':' Apoint_list ';'
157                 {}
158         ;
159
160 Bpoint_list:
161         Bpoint Bpoint_list
162                 {}
163         | Bpoint
164                 {}
165         ;
166
167 Bpoint:
168         '(' ConstOp ConstOp ')'
169                 {
170                 if (sp->num_beacons % REALLOC == 0) {
171                         if (sp->beacon == NULL)
172                                 sp->beacon = (BEACON *) malloc((sp->num_beacons
173                                         + REALLOC) * sizeof (BEACON));
174                         else
175                                 sp->beacon = (BEACON *) realloc(sp->beacon,
176                                         (sp->num_beacons + REALLOC) * 
177                                         sizeof (BEACON));
178                         if (sp->beacon == NULL)
179                                 return (yyerror("No memory available."));
180                 }
181                 sp->beacon[sp->num_beacons].x = $2;
182                 sp->beacon[sp->num_beacons].y = $3;
183                 check_point($2, $3);
184                 sp->num_beacons++;
185                 }
186         ;
187
188 Epoint_list:
189         Epoint Epoint_list
190                 {}
191         | Epoint
192                 {}
193         ;
194
195 Epoint:
196         '(' ConstOp ConstOp DirOp ')'
197                 {
198                 int     dir;
199
200                 if (sp->num_exits % REALLOC == 0) {
201                         if (sp->exit == NULL)
202                                 sp->exit = (EXIT *) malloc((sp->num_exits + 
203                                         REALLOC) * sizeof (EXIT));
204                         else
205                                 sp->exit = (EXIT *) realloc(sp->exit,
206                                         (sp->num_exits + REALLOC) * 
207                                         sizeof (EXIT));
208                         if (sp->exit == NULL)
209                                 return (yyerror("No memory available."));
210                 }
211                 dir = dir_no($4);
212                 sp->exit[sp->num_exits].x = $2;
213                 sp->exit[sp->num_exits].y = $3;
214                 sp->exit[sp->num_exits].dir = dir;
215                 check_edge($2, $3);
216                 check_edir($2, $3, dir);
217                 sp->num_exits++;
218                 }
219         ;
220
221 Apoint_list:
222         Apoint Apoint_list
223                 {}
224         | Apoint
225                 {}
226         ;
227
228 Apoint:
229         '(' ConstOp ConstOp DirOp ')'
230                 {
231                 int     dir;
232
233                 if (sp->num_airports % REALLOC == 0) {
234                         if (sp->airport == NULL)
235                                 sp->airport=(AIRPORT *)malloc((sp->num_airports
236                                         + REALLOC) * sizeof(AIRPORT));
237                         else
238                                 sp->airport = (AIRPORT *) realloc(sp->airport,
239                                         (sp->num_airports + REALLOC) * 
240                                         sizeof(AIRPORT));
241                         if (sp->airport == NULL)
242                                 return (yyerror("No memory available."));
243                 }
244                 dir = dir_no($4);
245                 sp->airport[sp->num_airports].x = $2;
246                 sp->airport[sp->num_airports].y = $3;
247                 sp->airport[sp->num_airports].dir = dir;
248                 check_point($2, $3);
249                 check_adir($2, $3, dir);
250                 sp->num_airports++;
251                 }
252         ;
253
254 Lline_list:
255         Lline Lline_list
256                 {}
257         | Lline
258                 {}
259         ;
260
261 Lline:
262         '[' '(' ConstOp ConstOp ')' '(' ConstOp ConstOp ')' ']'
263                 {
264                 if (sp->num_lines % REALLOC == 0) {
265                         if (sp->line == NULL)
266                                 sp->line = (LINE *) malloc((sp->num_lines + 
267                                         REALLOC) * sizeof (LINE));
268                         else
269                                 sp->line = (LINE *) realloc(sp->line,
270                                         (sp->num_lines + REALLOC) *
271                                         sizeof (LINE));
272                         if (sp->line == NULL)
273                                 return (yyerror("No memory available."));
274                 }
275                 sp->line[sp->num_lines].p1.x = $3;
276                 sp->line[sp->num_lines].p1.y = $4;
277                 sp->line[sp->num_lines].p2.x = $7;
278                 sp->line[sp->num_lines].p2.y = $8;
279                 check_line($3, $4, $7, $8);
280                 sp->num_lines++;
281                 }
282         ;
283 %%
284
285 check_edge(x, y)
286 {
287         if (!(x == 0) && !(x == sp->width - 1) && 
288             !(y == 0) && !(y == sp->height - 1))
289                 yyerror("edge value not on edge.");
290 }
291
292 check_point(x, y)
293 {
294         if (x < 1 || x >= sp->width - 1)
295                 yyerror("X value out of range.");
296         if (y < 1 || y >= sp->height - 1)
297                 yyerror("Y value out of range.");
298 }
299
300 check_linepoint(x, y)
301 {
302         if (x < 0 || x >= sp->width)
303                 yyerror("X value out of range.");
304         if (y < 0 || y >= sp->height)
305                 yyerror("Y value out of range.");
306 }
307
308 check_line(x1, y1, x2, y2)
309 {
310         int     d1, d2;
311
312         check_linepoint(x1, y1);
313         check_linepoint(x2, y2);
314
315         d1 = ABS(x2 - x1);
316         d2 = ABS(y2 - y1);
317
318         if (!(d1 == d2) && !(d1 == 0) && !(d2 == 0))
319                 yyerror("Bad line endpoints.");
320 }
321
322 yyerror(s)
323         char *s;
324 {
325         fprintf(stderr, "\"%s\": line %d: %s\n", file, line, s);
326         errors++;
327
328         return (errors);
329 }
330
331 check_edir(x, y, dir)
332 {
333         int     bad = 0;
334
335         if (x == sp->width - 1)
336                 x = 2;
337         else if (x != 0)
338                 x = 1;
339         if (y == sp->height - 1)
340                 y = 2;
341         else if (y != 0)
342                 y = 1;
343         
344         switch (x * 10 + y) {
345         case 00: if (dir != 3) bad++; break;
346         case 01: if (dir < 1 || dir > 3) bad++; break;
347         case 02: if (dir != 1) bad++; break;
348         case 10: if (dir < 3 || dir > 5) bad++; break;
349         case 11: break;
350         case 12: if (dir > 1 && dir < 7) bad++; break;
351         case 20: if (dir != 5) bad++; break;
352         case 21: if (dir < 5) bad++; break;
353         case 22: if (dir != 7) bad++; break;
354         default:
355                 yyerror("Unknown value in checkdir!  Get help!");
356                 break;
357         }
358         if (bad)
359                 yyerror("Bad direction for entrance at exit.");
360 }
361
362 check_adir(x, y, dir)
363 {
364 }
365
366 checkdefs()
367 {
368         int     err = 0;
369
370         if (sp->width == 0) {
371                 yyerror("'width' undefined.");
372                 err++;
373         }
374         if (sp->height == 0) {
375                 yyerror("'height' undefined.");
376                 err++;
377         }
378         if (sp->update_secs == 0) {
379                 yyerror("'update' undefined.");
380                 err++;
381         }
382         if (sp->newplane_time == 0) {
383                 yyerror("'newplane' undefined.");
384                 err++;
385         }
386         if (err)
387                 return (-1);
388         else
389                 return (0);
390 }