1 /* yacc.y								   */
2 /*									   */
3 /* Copyright (C) 1989, 1991, Craig E. Kolb				   */
4 /* All rights reserved.							   */
5 /*									   */
6 /* This software may be freely copied, modified, and redistributed,	   */
7 /* provided that this copyright notice is preserved on all copies.	   */
8 /*									   */
9 /* You may not distribute this software, in whole or in part, as part of   */
10 /* any commercial product without the express consent of the authors.	   */
11 /* 									   */
12 /* There is no warranty or other guarantee of fitness of this software	   */
13 /* for any purpose.  It is provided solely "as is".			   */
14 /* $Id: yacc.y,v 4.0.1.4 92/01/10 16:29:55 cek Exp Locker: cek $ */
15 %{
16 #include <stdlib.h>
17 #include <string.h>
18 #include "rayshade.h"
19 
20 #include "symtab.h"
21 #include "builtin.h"
22 
23 #include "libsurf/atmosphere.h"
24 #include "libsurf/surface.h"
25 #include "libtext/texture.h"
26 #include "libimage/image.h"
27 #include "libobj/geom.h"
28 #include "liblight/light.h"
29 #include "options.h"
30 #include "stats.h"
31 #include "viewing.h"
32 
33 #include "libobj/blob.h"
34 #include "libobj/box.h"
35 #include "libobj/cone.h"
36 #include "libobj/csg.h"
37 #include "libobj/cylinder.h"
38 #include "libobj/disc.h"
39 #include "libobj/grid.h"
40 #include "libobj/hf.h"
41 #include "libobj/instance.h"
42 #include "libobj/list.h"
43 #include "libobj/plane.h"
44 #include "libobj/poly.h"
45 #include "libobj/sphere.h"
46 #include "libobj/torus.h"
47 #include "libobj/triangle.h"
48 
49 #include "liblight/point.h"
50 #include "liblight/infinite.h"
51 #include "liblight/spot.h"
52 #include "liblight/jittered.h"
53 #include "liblight/extended.h"
54 
55 #include "libtext/blotch.h"
56 #include "libtext/bump.h"
57 #include "libtext/checker.h"
58 #include "libtext/cloud.h"
59 #include "libtext/fbm.h"
60 #include "libtext/fbmbump.h"
61 #include "libtext/gloss.h"
62 #include "libtext/imagetext.h"
63 #include "libtext/marble.h"
64 #include "libtext/mount.h"
65 #include "libtext/sky.h"
66 #include "libtext/stripe.h"
67 #include "libtext/windy.h"
68 #include "libtext/wood.h"
69 
70 #include "libsurf/fog.h"
71 #include "libsurf/fogdeck.h"
72 #include "libsurf/mist.h"
73 
74 #include "libcommon/rotate.h"
75 #include "libcommon/scale.h"
76 #include "libcommon/translate.h"
77 #include "libcommon/xform.h"
78 
79 Geom *NewAggregate();
80 char yyfilename[BUFSIZ];			/* Input filename */
81 GeomList *Defstack;				/* Geom definition stack. */
82 int Npoints = 0;				/* # of points in Polypoints */
83 Surface *tmpsurf;				/* Working surface */
84 SurfList *CurSurf;
85 Texture *CurText;				/* Working list of textures */
86 ImageText *Imagetext;				/* Working image texture */
87 Trans *TransHead, *TransTail;			/* Linked list of current transformations */
88 Atmosphere *CurEffect = (Atmosphere *)NULL;	/* Current atmos. effects */
89 PointList *Polypoints;				/* List of vertices */
90 MetaList *Metapoints, *Metapoint;
91 extern FILE *yyin;				/* input file pointer */
92 extern int yylineno;				/* Current line # in file */
93 extern Atmosphere *AtmosEffects;		/* atmospheric effects */
94 extern Medium TopMedium;			/* "air" */
95 extern void	GeomAddToDefined(),
96 		LightAddToDefined(),
97 		SurfaceAddToDefined();
98 extern Surface	*SurfaceGetNamed();
99 extern Geom 	*GeomGetNamed();
100 %}
101 %union {
102 	char *c;
103 	int i;
104 	Float d;
105 	Vector v;
106 	Vec2d uv;
107 	Color col;
108 	Atmosphere *atmos;
109 	Light *light;
110 	Surface *surf;
111 	Geom *obj;
112 	Texture *text;
113 	Mapping *map;
114 	Trans *trans;
115 	Expr *e;
116 	SymtabEntry *sym;
117 }
118 %token <d> tFLOAT
119 %token <c> tSTRING tFILENAME
120 %token tAPERTURE tAPPLYSURF
121 %token tBACKGROUND tBLOB tBLOTCH tBOX tBUMP tCONE tCYL tDIRECTIONAL tCURSURF
122 %token tEXTENDED tEYEP tFBM tFBMBUMP tFOCALDIST tFOG tFOGDECK tFOV tGLOSS tGRID
123 %token tHEIGHTFIELD tLIGHT tLIST tLOOKP tMARBLE tMAXDEPTH tMIST
124 %token tJITTER tNOJITTER tDEFINE
125 %token tOBJECT tOUTFILE  tSKY tDISC tDIFFERENCE tUNION tINTERSECT
126 %token tPLANE tPOINT tPOLY tROTATE tSPOT tPRINT
127 %token tSCALE tSCREEN tSPHERE tSURFACE
128 %token tTHRESH tTRANSLATE tTRANSFORM tTRIANGLE tTRIANGLEUV tUP tEND
129 %token tTEXTURE tCHECKER tWOOD tCONTRAST tCUTOFF tCLOUD
130 %token tAMBIENT tDIFFUSE tREFLECT tTRANSP tSPECULAR tSPECPOW
131 %token tINDEX tATMOSPHERE tNOSHADOW tAREA tTRANSLU tTORUS
132 %token tEYESEP tSHADOWTRANSP tREPORT tVERBOSE tQUIET tWINDOW tCROP tSTRIPE
133 %token tMAP tUV tSPHERICAL tCYLINDRICAL tPLANAR
134 %token tIMAGE tSMOOTH tCOMPONENT tTEXTSURF tRANGE tTILE tSTARTTIME tFRAMELENGTH
135 %token tNAME tFILTER tGAUSS tBODY tSAMPLE tEXTINCT tWINDY tMOUNT
136 %token tSHUTTER tFRAMES
137 %type <c> Filename
138 %type <e> AnimExpr MExpr ParenExpr
139 %type <d> Expr Float
140 %type <v> Vector
141 %type <uv> Vec2d
142 %type <col> Color Intensity Lightdef
143 %type <text> Texturetype
144 %type <i> SurfCompName IExpr CombineOp
145 %type <atmos> EffectType
146 %type <light> LightType
147 %type <obj> PrimType Primitive TransTextObj
148 %type <obj> Csg Aggregate Object TransObj ObjType
149 %type <obj> Blob Box Cone Cylinder Disc HeightField Plane Poly
150 %type <obj> Sphere Triangle Torus AggregateType List Grid AggregateCreate
151 %type <obj> NamedObject
152 %type <surf> Surface OptSurface NamedSurf
153 %type <surf> SurfSpec ModifyNamedSurf
154 %type <map> Mapping MapMethod OptMapping
155 %type <trans> TransformType
156 %type <sym> Symtabent
157 
158 %left '+' '-'
159 %left '*' '/' '%'
160 %left UMINUS
161 %right '^'
162 %%
163 Items		: /* empty */
164 		| Items Item
165 		;
166 Item		: Eyep
167 		| Lookp
168 		| Up
169 		| Fov
170 		| Screen
171 		| Window
172 		| Crop
173 		| Report
174 		| Aperture
175 		| Focaldist
176 		| Eyesep
177 		| Maxdepth
178 		| Sample
179 		| Filter
180 		| Contrast
181 		| Cutoff
182 		| Background
183 		| Shadowtransp
184 		| Light
185 		| SurfDef
186 		| CurSurf
187 		| Outfile
188 		| Instance
189 		| NameObject
190 		| GlobalEffects
191 		| Define
192 		| Frames
193 		| Starttime
194 		| Shutter
195 		| Framelength
196     		| Print
197 		;
198 Instance	: TransTextObj
199 		{
200 			if ($1) {
201 				/*
202 				 * Add instance to current object.
203 				 */
204 				$1->next = Defstack->obj->next;
205 				Defstack->obj->next = $1;
206 			}
207 		}
208 TransTextObj	: TransObj Textures
209 		{
210 			if ($$ && CurText) {
211 				$$->texture = TextAppend(CurText, $$->texture);
212 			}
213 			CurText = (Texture *)NULL;
214 		}
215 		;
216 TransObj	: Object Transforms
217 		{
218 			$$ = $1;
219 			if ($$ != (Geom *)NULL) {
220 				if (TransHead) {
221 					$$->trans = TransHead;
222 					$$->transtail = TransTail;
223 					/*
224 					 * We compose non-animated tranformation lists,
225 					 * so we're only animated if it's one long,
226 					 * or it's animated itself.
227 					 */
228 					if ($$->trans->assoc || $$->trans->next)
229 						/* geometry is animated...*/
230 						$$->animtrans = TRUE;
231 				}
232 			}
233 		}
234 		;
235 Object		: ObjType
236 		{
237 			if ($$)
238 				StatsAddRep($$);
239 		}
240 		| NamedObject
241 		;
242 ObjType		: Primitive
243 		| Aggregate
244 		;
245 Primitive	: PrimType
246 		{
247 			if ($$)
248 				$$->prims = 1;	/* one primitive */
249 		}
250 		;
251 PrimType	: Plane
252 		| Sphere
253 		| Box
254 		| Triangle
255 		| Cylinder
256 		| Cone
257 		| Poly
258 		| HeightField
259 		| Disc
260 		| Torus
261 		| Blob
262 		;
263 NameObject	: tNAME tSTRING TransTextObj
264 		{
265 			if ($3) {
266 				$3->name = $2;
267 				GeomAddToDefined($3);
268 			}
269 		};
270 Aggdefs		: Aggdefs Aggdef
271 		|
272 		;
273 Aggdef		: Instance
274 		| SurfDef
275 		| CurSurf
276 		| NameObject
277 		;
278 Textures	: Textures Texture
279 		|
280 		;
281 Texture		: tTEXTURE Texturetype Transforms
282 		{
283 			if ($2 != (Texture *)NULL) {
284 				/*
285 				 * Set transformation information.
286 				 */
287 				if (TransHead) {
288 					$2->trans = TransHead;
289 					/*
290 					 * We compose non-animated tranformation lists,
291 					 * so we're only animated if it's one long,
292 					 * or it's animated itself.
293 					 */
294 					if ($2->trans->assoc || $2->trans->next)
295 						/* texture transformation is animated...*/
296 						$2->animtrans = TRUE;
297 				}
298 				/*
299 				 * Walk to the end of list of textures and
300 				 * append new texture.  This is done so that
301 				 * textures are applied in the expected order.
302 				 */
303 				CurText = TextAppend($2, CurText);
304 			}
305 		}
306 		;
307 Texturetype	: tCHECKER Surface
308 		{
309 			$$ = TextCheckerCreate($2);
310 		}
311 		| tBLOTCH Expr Surface
312 		{
313 			$$ = TextBlotchCreate($2, $3);
314 		}
315 		| tBUMP Expr
316 		{
317 			$$ = TextBumpCreate($2);
318 		}
319 		| tMARBLE
320 		{
321 			$$ = TextMarbleCreate((char *)NULL);
322 		}
323 		| tMARBLE Filename
324 		{
325 			$$ = TextMarbleCreate($2);
326 		}
327 		| tFBM Expr Expr Expr Expr IExpr Expr
328 		{
329 			$$ = TextFBmCreate($2, $3, $4, $5, $6, $7,
330 						(char *)NULL);
331 		}
332 		| tFBM Expr Expr Expr Expr IExpr Expr Filename
333 		{
334 			$$ = TextFBmCreate($2, $3, $4, $5, $6, $7, $8);
335 		}
336 		| tFBMBUMP Expr Expr Expr Expr IExpr
337 		{
338 			$$ = TextFBmBumpCreate($2, $3, $4, $5, $6);
339 		}
340 		| tWOOD
341 		{
342 			$$ = TextWoodCreate();
343 		}
344 		| tGLOSS Expr
345 		{
346 			$$ = TextGlossCreate($2);
347 		}
348 		| tCLOUD Expr Expr Expr IExpr Expr Expr Expr
349 		{
350 			$$ = TextCloudCreate($2, $3, $4, $5, $6, $7, $8);
351 		}
352 		| tSKY Expr Expr Expr IExpr Expr Expr
353 		{
354 			$$ = TextSkyCreate($2, $3, $4, $5, $6, $7);
355 		}
356 		| ImageText
357 		{
358 			/*
359 			 * Image texturing has so many options
360 			 * that specification is keyword-based.
361 			 */
362 			if (Imagetext->image == (Image *)NULL)
363 				$$ = (Texture *)NULL;
364 			else
365 				$$ = TextCreate(Imagetext, ImageTextApply);
366 			Imagetext = (ImageText *)NULL;
367 		}
368 		| tSTRIPE Surface Expr Expr OptMapping
369 		{
370 			$$ = TextStripeCreate($2, $3, $4, $5);
371 		}
372 		| tWINDY Expr Expr Expr Expr IExpr Expr Expr Expr
373 		{
374 			$$ = TextWindyCreate($2, $3, $4, $5, $6, $7, $8, $9);
375 		}
376 		| tMOUNT Filename Expr Expr
377 		{
378 			$$ = TextMountCreate($2, $3, $4);
379 		}
380 		;
381 ImageText	: ImageTextType ImageTextOptions
382 		;
383 ImageTextType	: tIMAGE Filename
384 		{
385 			Imagetext = ImageTextCreate($2);
386 		}
387 		;
388 ImageTextOptions: ImageTextOptions ImageTextOption
389 		| /* EMPTY */
390 		;
391 ImageTextOption: tCOMPONENT SurfCompName
392 		{
393 			/* set texture to modify given component */
394 			ImageTextSetComponent(Imagetext, $2);
395 		}
396 		| tTILE Expr Expr
397 		{
398 			Imagetext->tileu = $2;
399 			Imagetext->tilev = $3;
400 		}
401 		| tTEXTSURF Surface
402 		{
403 			Imagetext->surf = $2;
404 		}
405 		| tRANGE Expr Expr
406 		{
407 			Imagetext->hi = $2;
408 			Imagetext->lo = $3;
409 		}
410 		| tSMOOTH
411 		{
412 			Imagetext->smooth = TRUE;
413 		}
414 		| Mapping
415 		{
416 			Imagetext->mapping = $1;
417 		};
418 NamedObject	: tOBJECT Surface tSTRING
419 		{
420 			Geom *otmp;
421 			/*
422 			 * Create an instance of the named object.
423 			 */
424 			otmp = GeomGetNamed($3);
425 			if (otmp == (Geom *)NULL)
426 				RLerror(RL_PANIC,
427 				  "There is no object named \"%s\".", $3);
428 			$$ = GeomInstanceCreate(otmp);
429 			$$->surf = $2;
430 			$$->prims = otmp->prims;
431 		}
432 		| tOBJECT tSTRING
433 		{
434 			Geom *otmp;
435 
436 			otmp = GeomGetNamed($2);
437 			if (otmp == (Geom *)NULL)
438 				RLerror(RL_PANIC,
439 				  "There is no object named \"%s\".", $2);
440 			$$ = GeomInstanceCreate(otmp);
441 			$$->surf = CurSurf->surf;
442 			$$->prims = otmp->prims;
443 		};
444 Transforms	: Transforms PostTransform
445 		| /* empty */
446 		{
447 			TransHead = TransTail = (Trans *)NULL;
448 		};
449 PostTransform	: TransformType
450 		{
451 			if (TransHead == (Trans *)NULL) {
452 				/* we're the list, head and tail */
453 				TransHead = TransTail = $1;
454 			} else {
455 				if ($1->animated || TransTail->animated) {
456 					/* new tail */
457 					$1->prev = TransTail;
458 					TransTail->next = $1;
459 					TransTail = $1;
460 				} else {
461 					/* collapse with tail */
462 					TransCompose(TransTail, $1, TransTail);
463 					TransFree($1);
464 				}
465 			}
466 		}
467 		;
468 TransformType	: tSCALE AnimExpr AnimExpr AnimExpr
469 		{
470 			$$ = TransScaleCreate();
471 			TransScaleSetX($$, $2);
472 			TransScaleSetY($$, $3);
473 			TransScaleSetZ($$, $4);
474 			if (!$$->animated)
475 				TransPropagate($$);
476 
477 		}
478 		| tTRANSLATE AnimExpr AnimExpr AnimExpr
479 		{
480 			$$ = TransTranslateCreate();
481 			TransTranslateSetX($$, $2);
482 			TransTranslateSetY($$, $3);
483 			TransTranslateSetZ($$, $4);
484 			if (!$$->animated)
485 				TransPropagate($$);
486 		}
487 		| tROTATE AnimExpr AnimExpr AnimExpr AnimExpr
488 		{
489 			$$ = TransRotateCreate();
490 			TransRotateSetX($$, $2);
491 			TransRotateSetY($$, $3);
492 			TransRotateSetZ($$, $4);
493 			TransRotateSetTheta($$, $5);
494 			if (!$$->animated)
495 				TransPropagate($$);
496 		}
497 		| tTRANSFORM	AnimExpr AnimExpr AnimExpr
498 				AnimExpr AnimExpr AnimExpr
499 				AnimExpr AnimExpr AnimExpr
500 		{
501 			$$ = TransXformCreate();
502 			TransXformSetX0($$, $2);
503 			TransXformSetY0($$, $3);
504 			TransXformSetZ0($$, $4);
505 			TransXformSetX1($$, $5);
506 			TransXformSetY1($$, $6);
507 			TransXformSetZ1($$, $7);
508 			TransXformSetX2($$, $8);
509 			TransXformSetY2($$, $9);
510 			TransXformSetZ2($$, $10);
511 			if (!$$->animated)
512 				TransPropagate($$);
513 		}
514 		| tTRANSFORM	AnimExpr AnimExpr AnimExpr
515 				AnimExpr AnimExpr AnimExpr
516 				AnimExpr AnimExpr AnimExpr
517 				AnimExpr AnimExpr AnimExpr
518 		{
519 			$$ = TransXformCreate();
520 			TransXformSetX0($$, $2);
521 			TransXformSetY0($$, $3);
522 			TransXformSetZ0($$, $4);
523 			TransXformSetX1($$, $5);
524 			TransXformSetY1($$, $6);
525 			TransXformSetZ1($$, $7);
526 			TransXformSetX2($$, $8);
527 			TransXformSetY2($$, $9);
528 			TransXformSetZ2($$, $10);
529 			TransXformSetXt($$, $11);
530 			TransXformSetYt($$, $12);
531 			TransXformSetZt($$, $13);
532 			if (!$$->animated)
533 				TransPropagate($$);
534 		};
535 Eyep		: tEYEP Vector Transforms
536 		{
537 			Camera.pos = $2;
538 			/*
539 			 * Eye can be transformed...
540 			if (CurMatrix) {
541 				PointTransform(&Camera.pos, CurMatrix);
542 				free((voidstar)CurMatrix);
543 				CurMatrix = (Matrix*)NULL;
544 			}
545 			 */
546 		}
547 		;
548 Lookp		: tLOOKP Vector
549 		{
550 			Camera.lookp = $2;
551 		}
552 		;
553 Up		: tUP Vector
554 		{
555 			Camera.up = $2;
556 		}
557 		;
558 Fov		: tFOV Expr Expr
559 		{
560 			Camera.hfov = $2;
561 			Camera.vfov = $3;
562 		}
563 		| tFOV Expr
564 		{
565 			Camera.hfov = $2;
566 			Camera.vfov = UNSET;
567 		}
568 		;
569 Sample		: tSAMPLE IExpr tJITTER
570 		{
571 			if (!Options.samples_set)
572 				Options.samples = $2;
573 			if (!Options.jitter_set)
574 				Options.jitter = TRUE;
575 		}
576 		| tSAMPLE IExpr tNOJITTER
577 		{
578 			if (!Options.samples_set)
579 				Options.samples = $2;
580 			if (!Options.jitter_set)
581 				Options.jitter = FALSE;
582 		}
583 		| tSAMPLE IExpr
584 		{
585 			if (!Options.samples_set)
586 				Options.samples = $2;
587 		}
588 		;
589 Filter		: tFILTER tBOX Expr
590 		{
591 			Options.gaussian = FALSE;
592 			Options.filterwidth = $3;
593 		}
594 		| tFILTER tBOX
595 		{
596 			Options.gaussian = FALSE;
597 		}
598 		| tFILTER tGAUSS Expr
599 		{
600 			Options.gaussian = TRUE;
601 			Options.filterwidth = $3;
602 		}
603 		| tFILTER tGAUSS
604 		{
605 			Options.gaussian = TRUE;
606 		};
607 Starttime	: tSTARTTIME Expr
608 		{
609 			Options.starttime = $2;
610 		};
611 Frames		: tFRAMES IExpr
612 		{
613 			if (!Options.totalframes_set)
614 				Options.totalframes = $2;
615 		};
616 Framelength	: tFRAMELENGTH Expr
617 		{
618 			Options.framelength = $2;
619 		};
620 Shutter		: tSHUTTER Expr
621 		{
622 			Options.shutterspeed = $2;
623 		};
624 Contrast	: tCONTRAST Expr Expr Expr
625 		{
626 			if (!Options.contrast_set) {
627 				Options.contrast.r = $2;
628 				Options.contrast.g = $3;
629 				Options.contrast.b = $4;
630 			}
631 		}
632 		;
633 Cutoff		: tCUTOFF Intensity
634 		{
635 			if (!Options.cutoff_set)
636 				Options.cutoff = $2;
637 		}
638 		;
639 Screen		: tSCREEN IExpr IExpr
640 		{
641 			if (!Options.resolution_set) {
642 				Screen.xres = $2;
643 				Screen.yres = $3;
644 			}
645 		}
646 		;
647 Window		: tWINDOW IExpr IExpr IExpr IExpr
648 		{
649 			if (!Options.window_set) {
650 				Options.window[LOW][X] = $2;
651 				Options.window[HIGH][X] = $3;
652 				Options.window[LOW][Y] = $4;
653 				Options.window[HIGH][Y] = $5;
654 				/*
655 				 * We must let ViewingSetup know
656 				 * that a window has been defined.
657 				 */
658 				Options.window_set = TRUE;
659 			}
660 		}
661 		;
662 Crop		: tCROP Expr Expr Expr Expr
663 		{
664 			if (!Options.crop_set) {
665 				Options.crop[LOW][X] = $2;
666 				Options.crop[HIGH][X] = $3;
667 				Options.crop[LOW][Y] = $4;
668 				Options.crop[HIGH][Y] = $5;
669 			}
670 		}
671 		;
672 Report		: tREPORT Verbose Quiet IExpr Filename
673 		{
674 			if (!Options.freq_set)
675 				Options.report_freq = $4;
676 			if (Options.statsname == (char *)NULL)
677 				Options.statsname = strsave($5);
678 		}
679 		| tREPORT Verbose Quiet IExpr
680 		{
681 			if (!Options.freq_set)
682 				Options.report_freq = $4;
683 		}
684 		| tREPORT Verbose Quiet Filename
685 		{
686 			if (Options.statsname == (char *)NULL)
687 				Options.statsname = strsave($4);
688 		}
689 		| tREPORT Verbose Quiet
690 		;
691 Verbose		: tVERBOSE
692 		{ Options.verbose = TRUE; }
693 		|
694 		;
695 Quiet		: tQUIET
696 		{ Options.quiet = TRUE; }
697 		|
698 		;
699 Aperture	: tAPERTURE Expr
700 		{
701 			Camera.aperture = $2;
702 		}
703 		;
704 Focaldist	: tFOCALDIST Expr
705 		{
706 			Camera.focaldist = $2;
707 		}
708 		;
709 Eyesep		: tEYESEP Expr
710 		{
711 			if (!Options.eyesep_set)
712 				Options.eyesep = $2;
713 		}
714 		;
715 Maxdepth	: tMAXDEPTH IExpr
716 		{
717 			if (!Options.maxdepth_set)
718 				Options.maxdepth = $2;
719 		}
720 		;
721 Background	: tBACKGROUND Color
722 		{
723 			Screen.background = $2;
724 		}
725 		;
726 Shadowtransp	: tSHADOWTRANSP
727 		{
728 			Options.shadowtransp = !Options.shadowtransp;
729 		}
730 		;
731 Light		: LightType
732 		{
733 			LightAddToDefined($1);
734 		}
735 		| LightType tNOSHADOW
736 		{
737 			$1->shadow = FALSE;
738 			LightAddToDefined($1);
739 		}
740 		| tLIGHT Intensity tAMBIENT
741 		{
742 			Options.ambient = $2;
743 		}
744 		| Lightdef tAREA Vector Vector IExpr Vector IExpr
745 		{
746 			extern void AreaLightCreate();
747 			/* Area light is strange in that the
748 			 * Creation routine does the installation.
749 			 */
750 			AreaLightCreate(&$1, &$3, &$4, $5, &$6, $7, TRUE);
751 		}
752 		| Lightdef tAREA Vector Vector IExpr Vector IExpr tNOSHADOW
753 		{
754 			extern void AreaLightCreate();
755 			/* Area light is strange in that the
756 			 * Creation routine does the installation.
757 			 */
758 			AreaLightCreate(&$1, &$3, &$4, $5, &$6, $7, FALSE);
759 		};
760 LightType	: Lightdef tPOINT Vector
761 		{
762 			$$ = LightPointCreate(&$1, &$3);
763 		}
764 		| Lightdef tDIRECTIONAL Vector
765 		{
766 			$$ = LightInfiniteCreate(&$1, &$3);
767 		}
768 		| Lightdef tEXTENDED Expr Vector
769 		{
770 			$$ = LightExtendedCreate(&$1, $3, &$4);
771 		}
772 		| Lightdef tSPOT Vector Vector Expr
773 		{
774 			$$ = LightSpotCreate(&$1, &$3, &$4, $5, 0., 0.);
775 		}
776 		| Lightdef tSPOT Vector Vector Expr Expr Expr
777 		{
778 			/* light <intens> spot from <to> coef inner_rad
779 					outer_rad */
780 			$$ = LightSpotCreate(&$1, &$3, &$4, $5, $6, $7);
781 		};
782 Lightdef	: tLIGHT Intensity
783 		{
784 			$$ = $2;
785 		}
786 		;
787 CurSurf		: tAPPLYSURF Surface
788 		{
789 			CurSurf->surf = $2;
790 		}
791 		;
792 OptSurface	: Surface
793 		| /* EMPTY */
794 		{
795 			$$ = CurSurf->surf;
796 		}
797 		;
798 Surface		: NamedSurf
799 		| ModifyNamedSurf
800 		| SurfSpec
801 		;
802 NamedSurf	: tSTRING
803 		{
804 			$$ = SurfaceGetNamed($1);
805 			/*
806 			 * Free up memory allocated for surf name.
807 			 * We bother doing this because for large models
808 			 * converted from 3.0, surfnames this can account
809 			 * for lots o' bytes.
810 			 */
811 			free((voidstar)$1);
812 		}
813 		| tCURSURF
814 		{
815 			extern Surface DefaultSurface;
816 
817 			if (CurSurf->surf)
818 				$$ = CurSurf->surf;
819 			else
820 				$$ = &DefaultSurface;
821 		}
822 		;
823 ModifyNamedSurf : CopyNamedSurf SurfComponent SurfComponents
824 		{
825 			$$ = tmpsurf;
826 			tmpsurf = (Surface *)NULL;
827 		}
828 		| CopyCurSurf SurfComponent SurfComponents
829 		{
830 			$$ = tmpsurf;
831 			tmpsurf = (Surface *)NULL;
832 		}
833 		;
834 CopyNamedSurf	: tSTRING
835 		{
836 			tmpsurf = SurfaceCopy(SurfaceGetNamed($1));
837 		}
838 		;
839 CopyCurSurf	: tCURSURF
840 		{
841 			extern Surface DefaultSurface;
842 			if (CurSurf->surf)
843 				tmpsurf = SurfaceCopy(CurSurf->surf);
844 			else
845 				tmpsurf = SurfaceCopy(&DefaultSurface);
846 		}
847 		;
848 SurfSpec	: SurfComponent SurfComponents
849 		{
850 			$$ = tmpsurf;
851 			tmpsurf = (Surface *)NULL;
852 		}
853 		;
854 SurfDef		: tSURFACE tSTRING Surface
855 		{
856 			tmpsurf = SurfaceCopy($3);
857 			tmpsurf->name = strsave($2);
858 			SurfaceAddToDefined(tmpsurf);
859 			tmpsurf = (Surface *)NULL;
860 		}
861 		| tSURFACE tSTRING
862 		{
863 			/* black surface */
864 			tmpsurf = SurfaceCreate();
865 			tmpsurf->name = strsave($2);
866 			SurfaceAddToDefined(tmpsurf);
867 			tmpsurf = (Surface *)NULL;
868 		}
869 		;
870 SurfComponents	: SurfComponents SurfComponent
871 		| /* EMPTY */
872 		;
873 SurfComponent	: Ambient
874 		| Diffuse
875 		| Specular
876 		| Specpow
877 		| Body
878 		| Reflect
879 		| Transp
880 		| Extinct
881 		| Index
882 		| Translu
883 		| Noshadow
884 		;
885 Ambient		: tAMBIENT Color
886 		{
887 			if (tmpsurf == (Surface *)NULL)
888 				tmpsurf = SurfaceCreate();
889 			tmpsurf->amb = $2;
890 		}
891 		;
892 Diffuse		: tDIFFUSE Color
893 		{
894 			if (tmpsurf == (Surface *)NULL)
895 				tmpsurf = SurfaceCreate();
896 			tmpsurf->diff = $2;
897 		}
898 		;
899 Specular	: tSPECULAR Color
900 		{
901 			if (tmpsurf == (Surface *)NULL)
902 				tmpsurf = SurfaceCreate();
903 			tmpsurf->spec = $2;
904 		}
905 		;
906 Body		: tBODY Color
907 		{
908 			if (tmpsurf == (Surface *)NULL)
909 				tmpsurf = SurfaceCreate();
910 			tmpsurf->body = $2;
911 		};
912 Extinct		: tEXTINCT Expr
913 		{
914 			if (tmpsurf == (Surface *)NULL)
915 				tmpsurf = SurfaceCreate();
916 			tmpsurf->statten = $2;
917 		};
918 Specpow		: tSPECPOW Expr
919 		{
920 			if (tmpsurf == (Surface *)NULL)
921 				tmpsurf = SurfaceCreate();
922 			tmpsurf->srexp = $2;
923 		}
924 		;
925 Reflect		: tREFLECT Expr
926 		{
927 			if (tmpsurf == (Surface *)NULL)
928 				tmpsurf = SurfaceCreate();
929 			tmpsurf->reflect = $2;
930 		}
931 		;
932 Transp		: tTRANSP Expr
933 		{
934 			if (tmpsurf == (Surface *)NULL)
935 				tmpsurf = SurfaceCreate();
936 			tmpsurf->transp = $2;
937 		}
938 		;
939 Index		: tINDEX Expr
940 		{
941 			if (tmpsurf == (Surface *)NULL)
942 				tmpsurf = SurfaceCreate();
943 			tmpsurf->index = $2;
944 		}
945 		;
946 Translu		: tTRANSLU Expr Color Expr
947 		{
948 			if (tmpsurf == (Surface *)NULL)
949 				tmpsurf = SurfaceCreate();
950 			tmpsurf->translucency = $2;
951 			tmpsurf->translu = $3;
952 			tmpsurf->stexp = $4;
953 		}
954 		;
955 Noshadow	: tNOSHADOW
956 		{
957 			if (tmpsurf == (Surface *)NULL)
958 				tmpsurf = SurfaceCreate();
959 			tmpsurf->noshadow = TRUE;
960 		}
961 		;
962 HeightField	: tHEIGHTFIELD Surface Filename
963 		{
964 			$$ = GeomHfCreate($3);
965 			if ($$)
966 				$$->surf = $2;
967 		}
968 		| tHEIGHTFIELD Filename
969 		{
970 			$$ = GeomHfCreate($2);
971 		}
972 		;
973 Poly		: tPOLY OptSurface Polypoints
974 		{
975 			$$ = GeomPolygonCreate(Polypoints, Npoints,
976 				Options.flipnorm);
977 			if ($$)
978 				$$->surf = $2;
979 			Polypoints = (PointList *)NULL;
980 			Npoints = 0;
981 		}
982 		;
983 Polypoints	: /* empty */
984 		| Polypoints Polypoint
985 		;
986 Polypoint	: Vector
987 		{
988 			PointList *ptmp;
989 
990 			ptmp = (PointList *)Malloc(sizeof(PointList));
991 			ptmp->vec = $1;
992 			ptmp->next = Polypoints;
993 			Polypoints = ptmp;
994 			Npoints++;
995 		}
996 		;
997 Aggregate	: AggregateDef
998 		{
999 			if (Defstack->obj) {
1000 				/*
1001 				 * Set object texture to current texture.
1002 				 */
1003 				Defstack->obj->texture = CurText;
1004 			}
1005 			CurText = (Texture *)NULL;
1006 			/*
1007 			 * Pop topmost object on stack.
1008 			 */
1009 			$$ = Defstack->obj;
1010 			Defstack = GeomStackPop(Defstack);
1011 			/* Pop current surface */
1012 			CurSurf = SurfPop(CurSurf);
1013 			/* Make current default surf aggregate's default */
1014 			$$->surf = CurSurf->surf;
1015 		}
1016 		;
1017 AggregateDef	: AggregateCreate Aggdefs tEND
1018 		{
1019 			/* Convert aggregate, pop stacks, etc. */
1020 			if ($1) {
1021 				if (Defstack->obj->next == (Geom *)NULL) {
1022 					RLerror(RL_WARN,
1023 						"Null object defined.\n");
1024 					Defstack->obj = (Geom *)NULL;
1025 				} else {
1026 					/*
1027 					 * Convert the linked list of objects
1028 					 * associated with the topmost object
1029 					 * to the appropriate aggregate type.
1030 					 */
1031 					Defstack->obj->prims=AggregateConvert(
1032 						Defstack->obj,
1033 						Defstack->obj->next);
1034 					/*
1035 					 * Make sure conversion worked OK.
1036 					 */
1037 					if (Defstack->obj->prims <= 0)
1038 						Defstack->obj = (Geom *)NULL;
1039 				}
1040 			}
1041 		}
1042 		;
1043 AggregateCreate	: AggregateType
1044 		{
1045 			if ($1) {
1046 				Defstack = GeomStackPush($1, Defstack);
1047 				CurSurf = SurfPush((Surface *)NULL, CurSurf);
1048 			}
1049 		};
1050 AggregateType	: List
1051 		| Grid
1052 		| Csg
1053 		;
1054 List		: tLIST
1055 		{
1056 			$$ = GeomListCreate();
1057 		}
1058 		;
1059 Grid		: tGRID IExpr IExpr IExpr
1060 		{
1061 			$$ = GeomGridCreate($2, $3, $4);
1062 		}
1063 		;
1064 Csg		: CombineOp
1065 		{
1066 			$$ = GeomCsgCreate($1);
1067 			Options.csg = TRUE;
1068 		}
1069 		;
1070 CombineOp	: tUNION
1071 		{
1072 		    $$ = CSG_UNION;
1073 		}
1074 		| tINTERSECT
1075 		{
1076 		    $$ = CSG_INTERSECT;
1077 		}
1078 		| tDIFFERENCE
1079 		{
1080 		    $$ = CSG_DIFFERENCE;
1081 		}
1082     		;
1083 Cone		: tCONE OptSurface Expr Vector Expr Vector
1084 		{
1085 			if (equal($3, $5)) {
1086 				/* It's really a cylinder */
1087 				$$ = GeomCylinderCreate($3, &$4, &$6);
1088 			} else
1089 				$$ = GeomConeCreate($3, &$4, $5, &$6);
1090 			if ($$)
1091 				$$->surf = $2;
1092 		}
1093 		;
1094 Cylinder	: tCYL OptSurface Expr Vector Vector
1095 		{
1096 			$$ = GeomCylinderCreate($3, &$4, &$5);
1097 			if ($$)
1098 				$$->surf = $2;
1099 		}
1100 		;
1101 Sphere		: tSPHERE OptSurface Expr Vector
1102 		{
1103 			$$ = GeomSphereCreate($3, &($4));
1104 			if ($$)
1105 				$$->surf = $2;
1106 		}
1107 		;
1108 Disc		: tDISC OptSurface Expr Vector Vector
1109 		{
1110 			$$ = GeomDiscCreate($3, &($4), &($5));
1111 			if ($$)
1112 				$$->surf = $2;
1113 		}
1114 		;
1115 Box		: tBOX OptSurface Vector Vector
1116 		{
1117 			$$ = GeomBoxCreate(&$3, &$4);
1118 			if ($$)
1119 				$$->surf = $2;
1120 		}
1121 		;
1122 Triangle	: tTRIANGLE OptSurface Vector Vector Vector
1123 		{
1124 			$$ = GeomTriangleCreate(FLATTRI, &($3), &($4), &($5),
1125 				(Vector *)NULL, (Vector *)NULL, (Vector *)NULL,
1126 				(Vec2d *)NULL, (Vec2d *)NULL, (Vec2d *)NULL,
1127 				Options.flipnorm);
1128 			if ($$)
1129 				$$->surf = $2;
1130 		}
1131 		| tTRIANGLE OptSurface  Vector Vector
1132 					Vector Vector
1133 					Vector Vector
1134 		{
1135 			$$ = GeomTriangleCreate(PHONGTRI, &($3), &($5),
1136 				&($7), &($4), &($6), &($8),
1137 				(Vec2d *)NULL, (Vec2d *)NULL, (Vec2d *)NULL,
1138 				Options.flipnorm);
1139 			if ($$)
1140 				$$->surf = $2;
1141 		}
1142 		| tTRIANGLEUV OptSurface Vector Vector Vec2d
1143 					 Vector Vector Vec2d
1144 					 Vector Vector Vec2d
1145 		{
1146 			$$ = GeomTriangleCreate(PHONGTRI, &($3), &($6), &($9),
1147 						&($4), &($7), &($10),
1148 						&($5), &($8), &($11),
1149 						Options.flipnorm);
1150 			if ($$)
1151 				$$->surf = $2;
1152 		}
1153 		;
1154 Plane		: tPLANE OptSurface Vector Vector
1155 		{
1156 			$$ = GeomPlaneCreate(&($3), &($4));
1157 			if ($$)
1158 				$$->surf = $2;
1159 		}
1160 		;
1161 Torus		: tTORUS OptSurface Expr Expr Vector Vector
1162 		{
1163 			$$ = GeomTorusCreate($3, $4, &($5), &($6));
1164 			if ($$)
1165 				$$->surf = $2;
1166 		}
1167 		;
1168 Blob		: tBLOB OptSurface Expr MetaPoints
1169 		{
1170 			$$ = GeomBlobCreate($3, Metapoints, Npoints);
1171 			if ($$)
1172 				$$->surf = $2;
1173 			Metapoints = (MetaList *)NULL;
1174 			Npoints = 0;
1175 		}
1176 		;
1177 MetaPoints	: /* empty */
1178 		| MetaPoints MetaPoint
1179 		;
1180 MetaPoint	: Expr Expr Expr Expr Expr
1181 		{
1182 			Metapoint = (MetaList *)Malloc(sizeof(MetaList));
1183 			Metapoint->mvec.c0 = $1;
1184 			Metapoint->mvec.rs = $2;
1185 			Metapoint->mvec.x = $3;
1186 			Metapoint->mvec.y = $4;
1187 			Metapoint->mvec.z = $5;
1188 			Metapoint->next = Metapoints;
1189 			Metapoints = Metapoint;
1190 			Npoints++;
1191 		}
1192 		;
1193 Outfile		: tOUTFILE Filename
1194 		{
1195 			if (Options.imgname != (char *)NULL)
1196 				/* Already set on command line. */
1197 				RLerror(RL_WARN,
1198 					"Ignoring output file name \"%s\".\n",
1199 					$2);
1200 			else
1201 				Options.imgname = strsave($2);
1202 		}
1203 		;
1204 GlobalEffects	: tATMOSPHERE Effects
1205 		{
1206 			AtmosEffects = CurEffect;
1207 			CurEffect = (Atmosphere *)NULL;
1208 		}
1209 		| tATMOSPHERE IExpr Effects
1210 		{
1211 			if ($2 <= 0.)
1212 				RLerror(RL_PANIC,
1213 				"Index of refraction must be positive.\n");
1214 			TopMedium.index = $2;
1215 			AtmosEffects = CurEffect;
1216 			CurEffect = (Atmosphere *)NULL;
1217 		}
1218 		;
1219 Effects		: Effects Effect
1220 		|
1221 		;
1222 Effect		: EffectType
1223 		{
1224 			$1->next = CurEffect;
1225 			CurEffect = $1;
1226 		}
1227 		;
1228 EffectType	: tMIST Color Color Expr Expr
1229 		{
1230 			$$ = AtmosMistCreate(&($2), &($3), $4, $5);
1231 		}
1232 		| tFOG Color Color
1233 		{
1234 			$$ = AtmosFogCreate(&($2), &($3));
1235 		}
1236 		| tFOGDECK Expr Expr Vector Expr IExpr Color Color
1237 		{
1238 			$$ = AtmosFogdeckCreate($2, $3, &$4, $5, $6, &$7, &$8);
1239 		}
1240 		;
1241 Color		: Expr Expr Expr
1242 		{
1243 			$$.r = $1;
1244 			$$.g = $2;
1245 			$$.b = $3;
1246 		}
1247 		;
1248 Vector		: Expr Expr Expr
1249 		{
1250 			$$.x = $1;
1251 			$$.y = $2;
1252 			$$.z = $3;
1253 		}
1254 		;
1255 Vec2d		: Expr Expr
1256 		{
1257 			$$.u = $1;
1258 			$$.v = $2;
1259 		}
1260 		;
1261 OptMapping	: Mapping
1262 		| /* EMPTY */
1263 		{
1264 			$$ = UVMappingCreate();
1265 		}
1266 		;
1267 Mapping		: tMAP MapMethod
1268 		{
1269 			$$ = $2;
1270 		}
1271 		;
1272 MapMethod	: tUV
1273 		{
1274 			$$ = UVMappingCreate();
1275 		}
1276 		| tSPHERICAL
1277 		{
1278 			$$ = SphereMappingCreate((Vector *)NULL,
1279 				(Vector *)NULL, (Vector *)NULL);
1280 		}
1281 		| tSPHERICAL Vector Vector Vector
1282 		{
1283 			/* origin up uaxis */
1284 			$$ = SphereMappingCreate(&$2, &$3, &$4);
1285 		}
1286 		| tCYLINDRICAL
1287 		{
1288 			$$ = CylMappingCreate((Vector *)NULL,
1289 				(Vector *)NULL, (Vector *)NULL);
1290 		}
1291 		| tCYLINDRICAL Vector Vector Vector
1292 		{
1293 			/* origin up uaxis */
1294 			$$ = CylMappingCreate(&$2, &$3, &$4);
1295 		}
1296 		| tPLANAR
1297 		{
1298 			$$ = LinearMappingCreate((Vector *)NULL,
1299 				(Vector *)NULL, (Vector *)NULL);
1300 		}
1301 		| tPLANAR Vector Vector Vector
1302 		{
1303 			/* origin up uaxis */
1304 			$$ = LinearMappingCreate(&$2, &$3, &$4);
1305 		}
1306 		;
1307 SurfCompName	: tAMBIENT
1308 		{
1309 			$$ = AMBIENT;
1310 		}
1311 		| tDIFFUSE
1312 		{
1313 			$$ = DIFFUSE;
1314 		}
1315 		| tBODY
1316 		{
1317 			$$ = BODY;
1318 		}
1319 		| tSPECULAR
1320 		{
1321 			$$ = SPECULAR;
1322 		}
1323 		| tREFLECT
1324 		{
1325 			$$ = REFLECT;
1326 		}
1327 		| tTRANSP
1328 		{
1329 			$$ = TRANSP;
1330 		}
1331 		| tSPECPOW
1332 		{
1333 			$$ = SPECPOW;
1334 		}
1335 		| tBUMP
1336 		{
1337 			$$ = BUMP;
1338 		}
1339 		| tINDEX
1340 		{
1341 			$$ = INDEX;
1342 		}
1343 		;
1344 Intensity	: Expr
1345 		{ $$.r = $$.g = $$.b = $1; }
1346 		| Color
1347 		;
1348 Print		: tPRINT Expr
1349 		{
1350 			fprintf(stderr,"%f\n",$2);
1351 		}
1352 Define		: tDEFINE tSTRING AnimExpr
1353 		{
1354 			SymtabAddEntry($2, $3->type, $3, NULL, $3->timevary, 0);
1355 		};
1356 IExpr		: Expr
1357 		{ $$ = (int)$1; }
1358 		;
1359 Expr		: Float
1360 		| ParenExpr
1361 		{
1362 			if (!$1->timevary) {
1363 				$$ = ExprEval($1);
1364 			} else {
1365 				RLerror(RL_PANIC, "Illegal expression use.\n");
1366 			}
1367 		}
1368 		;
1369 AnimExpr	: Float
1370 		{
1371 			$$ = ExprReuseFloatCreate($1);
1372 		}
1373 		| ParenExpr
1374 		;
1375 ParenExpr	: '(' MExpr ')'
1376 		{
1377 			$$ = $2;
1378 		};
1379 MExpr		: tFLOAT
1380 		{
1381 			$$ = ExprFloatCreate($1, FALSE);
1382 		}
1383 		| tSTRING
1384 		{
1385 			$$ = ExprFloatSymtabFind($1);
1386 		}
1387 		| Symtabent '(' MExpr ')'
1388 		{
1389 			$$ = ExprResolve1($3, $1->value.fp, $1->timevary);
1390 		}
1391 		| Symtabent '(' MExpr ',' MExpr ')'
1392 		{
1393 			$$ = ExprResolve2($3, $5,
1394 					$1->value.fp,
1395 					$1->timevary);
1396 		}
1397 		| Symtabent '(' MExpr ',' MExpr ',' MExpr ')'
1398 		{
1399 			$$ = ExprResolve3($3, $5, $7,
1400 					$1->value.fp,
1401 					$1->timevary);
1402 		}
1403 		| Symtabent '(' MExpr ',' MExpr ',' MExpr ',' MExpr ')'
1404 		{
1405 			$$ = ExprResolve4($3, $5, $7, $9,
1406 					$1->value.fp,
1407 					$1->timevary);
1408 		}
1409 		| Symtabent
1410 			'(' MExpr ',' MExpr ',' MExpr ',' MExpr ',' MExpr ')'
1411 		{
1412 			$$ = ExprResolve5($3, $5, $7, $9, $11,
1413 					$1->value.fp,
1414 					$1->timevary);
1415 		}
1416 		| '(' MExpr ')'
1417 		{
1418 			$$ = $2;
1419 		}
1420 		| MExpr '+' MExpr
1421 		{
1422 			$$ = ExprResolve2($1, $3, SumExpr, FALSE);
1423 		}
1424 		| MExpr '-' MExpr
1425 		{
1426 			$$ = ExprResolve2($1, $3, DiffExpr, FALSE);
1427 		}
1428 		| MExpr '*' MExpr
1429 		{
1430 			$$ = ExprResolve2($1, $3, MultExpr, FALSE);
1431 		}
1432 		| MExpr '/' MExpr
1433 		{
1434 			$$ = ExprResolve2($1, $3, DivideExpr, FALSE);
1435 		}
1436 		| MExpr '%' MExpr
1437 		{
1438 			$$ = ExprResolve2($1, $3, ModExpr, FALSE);
1439 		}
1440 		| '-' MExpr %prec UMINUS
1441 		{
1442 			$$ = ExprResolve1($2, NegateExpr, FALSE);
1443 		}
1444 		| '+' MExpr %prec UMINUS
1445 		{
1446 			$$ = $2;
1447 		}
1448 		| MExpr '^' MExpr
1449 		{
1450 			$$ = ExprResolve2($1, $3, pow, FALSE);
1451 		} ;
1452 Float		: tFLOAT
1453 		| '-' tFLOAT
1454 		{ $$ = -$2; }
1455 		| '+' tFLOAT
1456 		{ $$ = $2; };
1457 Filename	: tSTRING
1458 		| tFILENAME
1459 		;
1460 Symtabent	: tSTRING
1461 		{
1462 			$$ = SymtabBuiltinFind($1);
1463 		};
1464 %%
1465 /*
1466  * Issue error message containing filename and line number, and exit.
1467  */
1468 /*VARARGS1*/
yyerror(s,pat1,pat2)1469 yyerror(s, pat1, pat2)
1470 char *s, *pat1, *pat2;
1471 {
1472 	fprintf(stderr,"%s: Error: %s: line %d: ", Options.progname,
1473 			yyfilename, yylineno);
1474 	fprintf(stderr, s, pat1, pat2);
1475 	if (*s && s[strlen(s) -1] != '\n')
1476 		/* YACC doesn't put newlines on error messages. */
1477 		fprintf(stderr,"\n");
1478 	fflush(stderr);
1479 	exit(1);
1480 }
1481 
1482 Geom *
NewAggregate(obj)1483 NewAggregate(obj)
1484 Geom *obj;
1485 {
1486 	obj->name = Defstack->obj->name;
1487 	obj->next = Defstack->obj->next;
1488 	return obj;
1489 }
1490