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