xref: /netbsd/external/gpl2/groff/dist/src/preproc/pic/pic.y (revision 438b94bf)
1*438b94bfSchristos /*	$NetBSD: pic.y,v 1.2 2016/01/13 19:01:58 christos Exp $	*/
204ac863bSchristos 
304ac863bSchristos /* Copyright (C) 1989, 1990, 1991, 1992, 2000, 2001, 2002, 2003, 2004, 2005
404ac863bSchristos    Free Software Foundation, Inc.
504ac863bSchristos      Written by James Clark (jjc@jclark.com)
604ac863bSchristos 
704ac863bSchristos This file is part of groff.
804ac863bSchristos 
904ac863bSchristos groff is free software; you can redistribute it and/or modify it under
1004ac863bSchristos the terms of the GNU General Public License as published by the Free
1104ac863bSchristos Software Foundation; either version 2, or (at your option) any later
1204ac863bSchristos version.
1304ac863bSchristos 
1404ac863bSchristos groff is distributed in the hope that it will be useful, but WITHOUT ANY
1504ac863bSchristos WARRANTY; without even the implied warranty of MERCHANTABILITY or
1604ac863bSchristos FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
1704ac863bSchristos for more details.
1804ac863bSchristos 
1904ac863bSchristos You should have received a copy of the GNU General Public License along
2004ac863bSchristos with groff; see the file COPYING.  If not, write to the Free Software
2104ac863bSchristos Foundation, 51 Franklin St - Fifth Floor, Boston, MA 02110-1301, USA. */
2204ac863bSchristos %{
2304ac863bSchristos #include "pic.h"
2404ac863bSchristos #include "ptable.h"
2504ac863bSchristos #include "object.h"
2604ac863bSchristos 
2704ac863bSchristos extern int delim_flag;
2804ac863bSchristos extern void copy_rest_thru(const char *, const char *);
2904ac863bSchristos extern void copy_file_thru(const char *, const char *, const char *);
3004ac863bSchristos extern void push_body(const char *);
3104ac863bSchristos extern void do_for(char *var, double from, double to,
3204ac863bSchristos 		   int by_is_multiplicative, double by, char *body);
3304ac863bSchristos extern void do_lookahead();
3404ac863bSchristos 
3504ac863bSchristos /* Maximum number of characters produced by printf("%g") */
3604ac863bSchristos #define GDIGITS 14
3704ac863bSchristos 
3804ac863bSchristos int yylex();
3904ac863bSchristos void yyerror(const char *);
4004ac863bSchristos 
4104ac863bSchristos void reset(const char *nm);
4204ac863bSchristos void reset_all();
4304ac863bSchristos 
4404ac863bSchristos place *lookup_label(const char *);
4504ac863bSchristos void define_label(const char *label, const place *pl);
4604ac863bSchristos 
4704ac863bSchristos direction current_direction;
4804ac863bSchristos position current_position;
4904ac863bSchristos 
5004ac863bSchristos implement_ptable(place)
5104ac863bSchristos 
5204ac863bSchristos PTABLE(place) top_table;
5304ac863bSchristos 
5404ac863bSchristos PTABLE(place) *current_table = &top_table;
5504ac863bSchristos saved_state *current_saved_state = 0;
5604ac863bSchristos 
5704ac863bSchristos object_list olist;
5804ac863bSchristos 
5904ac863bSchristos const char *ordinal_postfix(int n);
6004ac863bSchristos const char *object_type_name(object_type type);
6104ac863bSchristos char *format_number(const char *form, double n);
6204ac863bSchristos char *do_sprintf(const char *form, const double *v, int nv);
6304ac863bSchristos 
6404ac863bSchristos %}
6504ac863bSchristos 
6604ac863bSchristos 
6704ac863bSchristos %union {
6804ac863bSchristos 	char *str;
6904ac863bSchristos 	int n;
7004ac863bSchristos 	double x;
7104ac863bSchristos 	struct { double x, y; } pair;
7204ac863bSchristos 	struct { double x; char *body; } if_data;
7304ac863bSchristos 	struct { char *str; const char *filename; int lineno; } lstr;
7404ac863bSchristos 	struct { double *v; int nv; int maxv; } dv;
7504ac863bSchristos 	struct { double val; int is_multiplicative; } by;
7604ac863bSchristos 	place pl;
7704ac863bSchristos 	object *obj;
7804ac863bSchristos 	corner crn;
7904ac863bSchristos 	path *pth;
8004ac863bSchristos 	object_spec *spec;
8104ac863bSchristos 	saved_state *pstate;
8204ac863bSchristos 	graphics_state state;
8304ac863bSchristos 	object_type obtype;
8404ac863bSchristos }
8504ac863bSchristos 
8604ac863bSchristos %token <str> LABEL
8704ac863bSchristos %token <str> VARIABLE
8804ac863bSchristos %token <x> NUMBER
8904ac863bSchristos %token <lstr> TEXT
9004ac863bSchristos %token <lstr> COMMAND_LINE
9104ac863bSchristos %token <str> DELIMITED
9204ac863bSchristos %token <n> ORDINAL
9304ac863bSchristos %token TH
9404ac863bSchristos %token LEFT_ARROW_HEAD
9504ac863bSchristos %token RIGHT_ARROW_HEAD
9604ac863bSchristos %token DOUBLE_ARROW_HEAD
9704ac863bSchristos %token LAST
9804ac863bSchristos %token UP
9904ac863bSchristos %token DOWN
10004ac863bSchristos %token LEFT
10104ac863bSchristos %token RIGHT
10204ac863bSchristos %token BOX
10304ac863bSchristos %token CIRCLE
10404ac863bSchristos %token ELLIPSE
10504ac863bSchristos %token ARC
10604ac863bSchristos %token LINE
10704ac863bSchristos %token ARROW
10804ac863bSchristos %token MOVE
10904ac863bSchristos %token SPLINE
11004ac863bSchristos %token HEIGHT
11104ac863bSchristos %token RADIUS
11204ac863bSchristos %token FIGNAME
11304ac863bSchristos %token WIDTH
11404ac863bSchristos %token DIAMETER
11504ac863bSchristos %token UP
11604ac863bSchristos %token DOWN
11704ac863bSchristos %token RIGHT
11804ac863bSchristos %token LEFT
11904ac863bSchristos %token FROM
12004ac863bSchristos %token TO
12104ac863bSchristos %token AT
12204ac863bSchristos %token WITH
12304ac863bSchristos %token BY
12404ac863bSchristos %token THEN
12504ac863bSchristos %token SOLID
12604ac863bSchristos %token DOTTED
12704ac863bSchristos %token DASHED
12804ac863bSchristos %token CHOP
12904ac863bSchristos %token SAME
13004ac863bSchristos %token INVISIBLE
13104ac863bSchristos %token LJUST
13204ac863bSchristos %token RJUST
13304ac863bSchristos %token ABOVE
13404ac863bSchristos %token BELOW
13504ac863bSchristos %token OF
13604ac863bSchristos %token THE
13704ac863bSchristos %token WAY
13804ac863bSchristos %token BETWEEN
13904ac863bSchristos %token AND
14004ac863bSchristos %token HERE
14104ac863bSchristos %token DOT_N
14204ac863bSchristos %token DOT_E
14304ac863bSchristos %token DOT_W
14404ac863bSchristos %token DOT_S
14504ac863bSchristos %token DOT_NE
14604ac863bSchristos %token DOT_SE
14704ac863bSchristos %token DOT_NW
14804ac863bSchristos %token DOT_SW
14904ac863bSchristos %token DOT_C
15004ac863bSchristos %token DOT_START
15104ac863bSchristos %token DOT_END
15204ac863bSchristos %token DOT_X
15304ac863bSchristos %token DOT_Y
15404ac863bSchristos %token DOT_HT
15504ac863bSchristos %token DOT_WID
15604ac863bSchristos %token DOT_RAD
15704ac863bSchristos %token SIN
15804ac863bSchristos %token COS
15904ac863bSchristos %token ATAN2
16004ac863bSchristos %token LOG
16104ac863bSchristos %token EXP
16204ac863bSchristos %token SQRT
16304ac863bSchristos %token K_MAX
16404ac863bSchristos %token K_MIN
16504ac863bSchristos %token INT
16604ac863bSchristos %token RAND
16704ac863bSchristos %token SRAND
16804ac863bSchristos %token COPY
16904ac863bSchristos %token THRU
17004ac863bSchristos %token TOP
17104ac863bSchristos %token BOTTOM
17204ac863bSchristos %token UPPER
17304ac863bSchristos %token LOWER
17404ac863bSchristos %token SH
17504ac863bSchristos %token PRINT
17604ac863bSchristos %token CW
17704ac863bSchristos %token CCW
17804ac863bSchristos %token FOR
17904ac863bSchristos %token DO
18004ac863bSchristos %token IF
18104ac863bSchristos %token ELSE
18204ac863bSchristos %token ANDAND
18304ac863bSchristos %token OROR
18404ac863bSchristos %token NOTEQUAL
18504ac863bSchristos %token EQUALEQUAL
18604ac863bSchristos %token LESSEQUAL
18704ac863bSchristos %token GREATEREQUAL
18804ac863bSchristos %token LEFT_CORNER
18904ac863bSchristos %token RIGHT_CORNER
19004ac863bSchristos %token NORTH
19104ac863bSchristos %token SOUTH
19204ac863bSchristos %token EAST
19304ac863bSchristos %token WEST
19404ac863bSchristos %token CENTER
19504ac863bSchristos %token END
19604ac863bSchristos %token START
19704ac863bSchristos %token RESET
19804ac863bSchristos %token UNTIL
19904ac863bSchristos %token PLOT
20004ac863bSchristos %token THICKNESS
20104ac863bSchristos %token FILL
20204ac863bSchristos %token COLORED
20304ac863bSchristos %token OUTLINED
20404ac863bSchristos %token SHADED
20504ac863bSchristos %token ALIGNED
20604ac863bSchristos %token SPRINTF
20704ac863bSchristos %token COMMAND
20804ac863bSchristos 
20904ac863bSchristos %token DEFINE
21004ac863bSchristos %token UNDEF
21104ac863bSchristos 
21204ac863bSchristos %left '.'
21304ac863bSchristos 
21404ac863bSchristos /* this ensures that plot 17 "%g" parses as (plot 17 "%g") */
21504ac863bSchristos %left PLOT
21604ac863bSchristos %left TEXT SPRINTF
21704ac863bSchristos 
21804ac863bSchristos /* give text adjustments higher precedence than TEXT, so that
21904ac863bSchristos box "foo" above ljust == box ("foo" above ljust)
22004ac863bSchristos */
22104ac863bSchristos 
22204ac863bSchristos %left LJUST RJUST ABOVE BELOW
22304ac863bSchristos 
22404ac863bSchristos %left LEFT RIGHT
22504ac863bSchristos /* Give attributes that take an optional expression a higher
22604ac863bSchristos precedence than left and right, so that eg `line chop left'
22704ac863bSchristos parses properly. */
22804ac863bSchristos %left CHOP SOLID DASHED DOTTED UP DOWN FILL COLORED OUTLINED
22904ac863bSchristos %left LABEL
23004ac863bSchristos 
23104ac863bSchristos %left VARIABLE NUMBER '(' SIN COS ATAN2 LOG EXP SQRT K_MAX K_MIN INT RAND SRAND LAST
23204ac863bSchristos %left ORDINAL HERE '`'
23304ac863bSchristos 
23404ac863bSchristos %left BOX CIRCLE ELLIPSE ARC LINE ARROW SPLINE '['
23504ac863bSchristos 
23604ac863bSchristos /* these need to be lower than '-' */
23704ac863bSchristos %left HEIGHT RADIUS WIDTH DIAMETER FROM TO AT THICKNESS
23804ac863bSchristos 
23904ac863bSchristos /* these must have higher precedence than CHOP so that `label %prec CHOP'
24004ac863bSchristos works */
24104ac863bSchristos %left DOT_N DOT_E DOT_W DOT_S DOT_NE DOT_SE DOT_NW DOT_SW DOT_C
24204ac863bSchristos %left DOT_START DOT_END TOP BOTTOM LEFT_CORNER RIGHT_CORNER
24304ac863bSchristos %left UPPER LOWER NORTH SOUTH EAST WEST CENTER START END
24404ac863bSchristos 
24504ac863bSchristos %left ','
24604ac863bSchristos %left OROR
24704ac863bSchristos %left ANDAND
24804ac863bSchristos %left EQUALEQUAL NOTEQUAL
24904ac863bSchristos %left '<' '>' LESSEQUAL GREATEREQUAL
25004ac863bSchristos 
25104ac863bSchristos %left BETWEEN OF
25204ac863bSchristos %left AND
25304ac863bSchristos 
25404ac863bSchristos %left '+' '-'
25504ac863bSchristos %left '*' '/' '%'
25604ac863bSchristos %right '!'
25704ac863bSchristos %right '^'
25804ac863bSchristos 
25904ac863bSchristos %type <x> expr any_expr text_expr
26004ac863bSchristos %type <by> optional_by
26104ac863bSchristos %type <pair> expr_pair position_not_place
26204ac863bSchristos %type <if_data> simple_if
26304ac863bSchristos %type <obj> nth_primitive
26404ac863bSchristos %type <crn> corner
26504ac863bSchristos %type <pth> path label_path relative_path
26604ac863bSchristos %type <pl> place label element element_list middle_element_list
26704ac863bSchristos %type <spec> object_spec
26804ac863bSchristos %type <pair> position
26904ac863bSchristos %type <obtype> object_type
27004ac863bSchristos %type <n> optional_ordinal_last ordinal
27104ac863bSchristos %type <str> macro_name until
27204ac863bSchristos %type <dv> sprintf_args
27304ac863bSchristos %type <lstr> text print_args print_arg
27404ac863bSchristos 
27504ac863bSchristos %%
27604ac863bSchristos 
27704ac863bSchristos top:
27804ac863bSchristos 	optional_separator
27904ac863bSchristos 	| element_list
28004ac863bSchristos 		{
28104ac863bSchristos 		  if (olist.head)
28204ac863bSchristos 		    print_picture(olist.head);
28304ac863bSchristos 		}
28404ac863bSchristos 	;
28504ac863bSchristos 
28604ac863bSchristos 
28704ac863bSchristos element_list:
28804ac863bSchristos 	optional_separator middle_element_list optional_separator
28904ac863bSchristos 		{ $$ = $2; }
29004ac863bSchristos 	;
29104ac863bSchristos 
29204ac863bSchristos middle_element_list:
29304ac863bSchristos 	element
29404ac863bSchristos 		{ $$ = $1; }
29504ac863bSchristos 	| middle_element_list separator element
29604ac863bSchristos 		{ $$ = $1; }
29704ac863bSchristos 	;
29804ac863bSchristos 
29904ac863bSchristos optional_separator:
30004ac863bSchristos 	/* empty */
30104ac863bSchristos 	| separator
30204ac863bSchristos 	;
30304ac863bSchristos 
30404ac863bSchristos separator:
30504ac863bSchristos 	';'
30604ac863bSchristos 	| separator ';'
30704ac863bSchristos 	;
30804ac863bSchristos 
30904ac863bSchristos placeless_element:
31004ac863bSchristos 	FIGNAME '=' macro_name
31104ac863bSchristos 		{
31204ac863bSchristos 		  a_delete graphname;
31304ac863bSchristos 		  graphname = new char[strlen($3) + 1];
31404ac863bSchristos 		  strcpy(graphname, $3);
31504ac863bSchristos 		  a_delete $3;
31604ac863bSchristos 		}
31704ac863bSchristos 	|
31804ac863bSchristos 	VARIABLE '=' any_expr
31904ac863bSchristos 		{
32004ac863bSchristos 		  define_variable($1, $3);
32104ac863bSchristos 		  a_delete $1;
32204ac863bSchristos 		}
32304ac863bSchristos 	| VARIABLE ':' '=' any_expr
32404ac863bSchristos 		{
32504ac863bSchristos 		  place *p = lookup_label($1);
32604ac863bSchristos 		  if (!p) {
32704ac863bSchristos 		    lex_error("variable `%1' not defined", $1);
32804ac863bSchristos 		    YYABORT;
32904ac863bSchristos 		  }
33004ac863bSchristos 		  p->obj = 0;
33104ac863bSchristos 		  p->x = $4;
33204ac863bSchristos 		  p->y = 0.0;
33304ac863bSchristos 		  a_delete $1;
33404ac863bSchristos 		}
33504ac863bSchristos 	| UP
33604ac863bSchristos 		{ current_direction = UP_DIRECTION; }
33704ac863bSchristos 	| DOWN
33804ac863bSchristos 		{ current_direction = DOWN_DIRECTION; }
33904ac863bSchristos 	| LEFT
34004ac863bSchristos 		{ current_direction = LEFT_DIRECTION; }
34104ac863bSchristos 	| RIGHT
34204ac863bSchristos 		{ current_direction = RIGHT_DIRECTION; }
34304ac863bSchristos 	| COMMAND_LINE
34404ac863bSchristos 		{
34504ac863bSchristos 		  olist.append(make_command_object($1.str, $1.filename,
34604ac863bSchristos 						   $1.lineno));
34704ac863bSchristos 		}
34804ac863bSchristos 	| COMMAND print_args
34904ac863bSchristos 		{
35004ac863bSchristos 		  olist.append(make_command_object($2.str, $2.filename,
35104ac863bSchristos 						   $2.lineno));
35204ac863bSchristos 		}
35304ac863bSchristos 	| PRINT print_args
35404ac863bSchristos 		{
35504ac863bSchristos 		  fprintf(stderr, "%s\n", $2.str);
35604ac863bSchristos 		  a_delete $2.str;
35704ac863bSchristos 		  fflush(stderr);
35804ac863bSchristos 		}
35904ac863bSchristos 	| SH
36004ac863bSchristos 		{ delim_flag = 1; }
36104ac863bSchristos 	  DELIMITED
36204ac863bSchristos 		{
36304ac863bSchristos 		  delim_flag = 0;
36404ac863bSchristos 		  if (safer_flag)
36504ac863bSchristos 		    lex_error("unsafe to run command `%1'", $3);
36604ac863bSchristos 		  else
36704ac863bSchristos 		    system($3);
36804ac863bSchristos 		  a_delete $3;
36904ac863bSchristos 		}
37004ac863bSchristos 	| COPY TEXT
37104ac863bSchristos 		{
37204ac863bSchristos 		  if (yychar < 0)
37304ac863bSchristos 		    do_lookahead();
37404ac863bSchristos 		  do_copy($2.str);
37504ac863bSchristos 		  // do not delete the filename
37604ac863bSchristos 		}
37704ac863bSchristos 	| COPY TEXT THRU
37804ac863bSchristos 		{ delim_flag = 2; }
37904ac863bSchristos 	  DELIMITED
38004ac863bSchristos 		{ delim_flag = 0; }
38104ac863bSchristos 	  until
38204ac863bSchristos 		{
38304ac863bSchristos 		  if (yychar < 0)
38404ac863bSchristos 		    do_lookahead();
38504ac863bSchristos 		  copy_file_thru($2.str, $5, $7);
38604ac863bSchristos 		  // do not delete the filename
38704ac863bSchristos 		  a_delete $5;
38804ac863bSchristos 		  a_delete $7;
38904ac863bSchristos 		}
39004ac863bSchristos 	| COPY THRU
39104ac863bSchristos 		{ delim_flag = 2; }
39204ac863bSchristos 	  DELIMITED
39304ac863bSchristos 		{ delim_flag = 0; }
39404ac863bSchristos 	  until
39504ac863bSchristos 		{
39604ac863bSchristos 		  if (yychar < 0)
39704ac863bSchristos 		    do_lookahead();
39804ac863bSchristos 		  copy_rest_thru($4, $6);
39904ac863bSchristos 		  a_delete $4;
40004ac863bSchristos 		  a_delete $6;
40104ac863bSchristos 		}
40204ac863bSchristos 	| FOR VARIABLE '=' expr TO expr optional_by DO
40304ac863bSchristos 	  	{ delim_flag = 1; }
40404ac863bSchristos 	  DELIMITED
40504ac863bSchristos 	  	{
40604ac863bSchristos 		  delim_flag = 0;
40704ac863bSchristos 		  if (yychar < 0)
40804ac863bSchristos 		    do_lookahead();
40904ac863bSchristos 		  do_for($2, $4, $6, $7.is_multiplicative, $7.val, $10);
41004ac863bSchristos 		}
41104ac863bSchristos 	| simple_if
41204ac863bSchristos 		{
41304ac863bSchristos 		  if (yychar < 0)
41404ac863bSchristos 		    do_lookahead();
41504ac863bSchristos 		  if ($1.x != 0.0)
41604ac863bSchristos 		    push_body($1.body);
41704ac863bSchristos 		  a_delete $1.body;
41804ac863bSchristos 		}
41904ac863bSchristos 	| simple_if ELSE
42004ac863bSchristos 		{ delim_flag = 1; }
42104ac863bSchristos 	  DELIMITED
42204ac863bSchristos 		{
42304ac863bSchristos 		  delim_flag = 0;
42404ac863bSchristos 		  if (yychar < 0)
42504ac863bSchristos 		    do_lookahead();
42604ac863bSchristos 		  if ($1.x != 0.0)
42704ac863bSchristos 		    push_body($1.body);
42804ac863bSchristos 		  else
42904ac863bSchristos 		    push_body($4);
43004ac863bSchristos 		  a_delete $1.body;
43104ac863bSchristos 		  a_delete $4;
43204ac863bSchristos 		}
43304ac863bSchristos 	| reset_variables
43404ac863bSchristos 	| RESET
43504ac863bSchristos 		{ define_variable("scale", 1.0); }
43604ac863bSchristos 	;
43704ac863bSchristos 
43804ac863bSchristos macro_name:
43904ac863bSchristos 	VARIABLE
44004ac863bSchristos 	| LABEL
44104ac863bSchristos 	;
44204ac863bSchristos 
44304ac863bSchristos reset_variables:
44404ac863bSchristos 	RESET VARIABLE
44504ac863bSchristos 		{
44604ac863bSchristos 		  reset($2);
44704ac863bSchristos 		  a_delete $2;
44804ac863bSchristos 		}
44904ac863bSchristos 	| reset_variables VARIABLE
45004ac863bSchristos 		{
45104ac863bSchristos 		  reset($2);
45204ac863bSchristos 		  a_delete $2;
45304ac863bSchristos 		}
45404ac863bSchristos 	| reset_variables ',' VARIABLE
45504ac863bSchristos 		{
45604ac863bSchristos 		  reset($3);
45704ac863bSchristos 		  a_delete $3;
45804ac863bSchristos 		}
45904ac863bSchristos 	;
46004ac863bSchristos 
46104ac863bSchristos print_args:
46204ac863bSchristos 	print_arg
46304ac863bSchristos 		{ $$ = $1; }
46404ac863bSchristos 	| print_args print_arg
46504ac863bSchristos 		{
46604ac863bSchristos 		  $$.str = new char[strlen($1.str) + strlen($2.str) + 1];
46704ac863bSchristos 		  strcpy($$.str, $1.str);
46804ac863bSchristos 		  strcat($$.str, $2.str);
46904ac863bSchristos 		  a_delete $1.str;
47004ac863bSchristos 		  a_delete $2.str;
47104ac863bSchristos 		  if ($1.filename) {
47204ac863bSchristos 		    $$.filename = $1.filename;
47304ac863bSchristos 		    $$.lineno = $1.lineno;
47404ac863bSchristos 		  }
47504ac863bSchristos 		  else if ($2.filename) {
47604ac863bSchristos 		    $$.filename = $2.filename;
47704ac863bSchristos 		    $$.lineno = $2.lineno;
47804ac863bSchristos 		  }
47904ac863bSchristos 		}
48004ac863bSchristos 	;
48104ac863bSchristos 
48204ac863bSchristos print_arg:
48304ac863bSchristos   	expr							%prec ','
48404ac863bSchristos 		{
48504ac863bSchristos 		  $$.str = new char[GDIGITS + 1];
48604ac863bSchristos 		  sprintf($$.str, "%g", $1);
48704ac863bSchristos 		  $$.filename = 0;
48804ac863bSchristos 		  $$.lineno = 0;
48904ac863bSchristos 		}
49004ac863bSchristos 	| text
49104ac863bSchristos 		{ $$ = $1; }
49204ac863bSchristos 	| position						%prec ','
49304ac863bSchristos 		{
49404ac863bSchristos 		  $$.str = new char[GDIGITS + 2 + GDIGITS + 1];
49504ac863bSchristos 		  sprintf($$.str, "%g, %g", $1.x, $1.y);
49604ac863bSchristos 		  $$.filename = 0;
49704ac863bSchristos 		  $$.lineno = 0;
49804ac863bSchristos 		}
49904ac863bSchristos 	;
50004ac863bSchristos 
50104ac863bSchristos simple_if:
50204ac863bSchristos 	IF any_expr THEN
50304ac863bSchristos 		{ delim_flag = 1; }
50404ac863bSchristos 	DELIMITED
50504ac863bSchristos 		{
50604ac863bSchristos 		  delim_flag = 0;
50704ac863bSchristos 		  $$.x = $2;
50804ac863bSchristos 		  $$.body = $5;
50904ac863bSchristos 		}
51004ac863bSchristos 	;
51104ac863bSchristos 
51204ac863bSchristos until:
51304ac863bSchristos 	/* empty */
51404ac863bSchristos 		{ $$ = 0; }
51504ac863bSchristos 	| UNTIL TEXT
51604ac863bSchristos 		{ $$ = $2.str; }
51704ac863bSchristos 	;
51804ac863bSchristos 
51904ac863bSchristos any_expr:
52004ac863bSchristos 	expr
52104ac863bSchristos 		{ $$ = $1; }
52204ac863bSchristos 	| text_expr
52304ac863bSchristos 		{ $$ = $1; }
52404ac863bSchristos 	;
52504ac863bSchristos 
52604ac863bSchristos text_expr:
52704ac863bSchristos 	text EQUALEQUAL text
52804ac863bSchristos 		{
52904ac863bSchristos 		  $$ = strcmp($1.str, $3.str) == 0;
53004ac863bSchristos 		  a_delete $1.str;
53104ac863bSchristos 		  a_delete $3.str;
53204ac863bSchristos 		}
53304ac863bSchristos 	| text NOTEQUAL text
53404ac863bSchristos 		{
53504ac863bSchristos 		  $$ = strcmp($1.str, $3.str) != 0;
53604ac863bSchristos 		  a_delete $1.str;
53704ac863bSchristos 		  a_delete $3.str;
53804ac863bSchristos 		}
53904ac863bSchristos 	| text_expr ANDAND text_expr
54004ac863bSchristos 		{ $$ = ($1 != 0.0 && $3 != 0.0); }
54104ac863bSchristos 	| text_expr ANDAND expr
54204ac863bSchristos 		{ $$ = ($1 != 0.0 && $3 != 0.0); }
54304ac863bSchristos 	| expr ANDAND text_expr
54404ac863bSchristos 		{ $$ = ($1 != 0.0 && $3 != 0.0); }
54504ac863bSchristos 	| text_expr OROR text_expr
54604ac863bSchristos 		{ $$ = ($1 != 0.0 || $3 != 0.0); }
54704ac863bSchristos 	| text_expr OROR expr
54804ac863bSchristos 		{ $$ = ($1 != 0.0 || $3 != 0.0); }
54904ac863bSchristos 	| expr OROR text_expr
55004ac863bSchristos 		{ $$ = ($1 != 0.0 || $3 != 0.0); }
55104ac863bSchristos 	| '!' text_expr
55204ac863bSchristos 		{ $$ = ($2 == 0.0); }
55304ac863bSchristos 	;
55404ac863bSchristos 
55504ac863bSchristos 
55604ac863bSchristos optional_by:
55704ac863bSchristos 	/* empty */
55804ac863bSchristos 		{
55904ac863bSchristos 		  $$.val = 1.0;
56004ac863bSchristos 		  $$.is_multiplicative = 0;
56104ac863bSchristos 		}
56204ac863bSchristos 	| BY expr
56304ac863bSchristos 		{
56404ac863bSchristos 		  $$.val = $2;
56504ac863bSchristos 		  $$.is_multiplicative = 0;
56604ac863bSchristos 		}
56704ac863bSchristos 	| BY '*' expr
56804ac863bSchristos 		{
56904ac863bSchristos 		  $$.val = $3;
57004ac863bSchristos 		  $$.is_multiplicative = 1;
57104ac863bSchristos 		}
57204ac863bSchristos 	;
57304ac863bSchristos 
57404ac863bSchristos element:
57504ac863bSchristos 	object_spec
57604ac863bSchristos 		{
57704ac863bSchristos 		  $$.obj = $1->make_object(&current_position,
57804ac863bSchristos 					   &current_direction);
57904ac863bSchristos 		  if ($$.obj == 0)
58004ac863bSchristos 		    YYABORT;
58104ac863bSchristos 		  delete $1;
58204ac863bSchristos 		  if ($$.obj)
58304ac863bSchristos 		    olist.append($$.obj);
58404ac863bSchristos 		  else {
58504ac863bSchristos 		    $$.x = current_position.x;
58604ac863bSchristos 		    $$.y = current_position.y;
58704ac863bSchristos 		  }
58804ac863bSchristos 		}
58904ac863bSchristos 	| LABEL ':' optional_separator element
59004ac863bSchristos 		{
59104ac863bSchristos 		  $$ = $4;
59204ac863bSchristos 		  define_label($1, & $$);
59304ac863bSchristos 		  a_delete $1;
59404ac863bSchristos 		}
59504ac863bSchristos 	| LABEL ':' optional_separator position_not_place
59604ac863bSchristos 		{
59704ac863bSchristos 		  $$.obj = 0;
59804ac863bSchristos 		  $$.x = $4.x;
59904ac863bSchristos 		  $$.y = $4.y;
60004ac863bSchristos 		  define_label($1, & $$);
60104ac863bSchristos 		  a_delete $1;
60204ac863bSchristos 		}
60304ac863bSchristos 	| LABEL ':' optional_separator place
60404ac863bSchristos 		{
60504ac863bSchristos 		  $$ = $4;
60604ac863bSchristos 		  define_label($1, & $$);
60704ac863bSchristos 		  a_delete $1;
60804ac863bSchristos 		}
60904ac863bSchristos 	| '{'
61004ac863bSchristos 		{
61104ac863bSchristos 		  $<state>$.x = current_position.x;
61204ac863bSchristos 		  $<state>$.y = current_position.y;
61304ac863bSchristos 		  $<state>$.dir = current_direction;
61404ac863bSchristos 		}
61504ac863bSchristos 	  element_list '}'
61604ac863bSchristos 		{
61704ac863bSchristos 		  current_position.x = $<state>2.x;
61804ac863bSchristos 		  current_position.y = $<state>2.y;
61904ac863bSchristos 		  current_direction = $<state>2.dir;
62004ac863bSchristos 		}
62104ac863bSchristos 	  optional_element
62204ac863bSchristos 		{
62304ac863bSchristos 		  $$ = $3;
62404ac863bSchristos 		}
62504ac863bSchristos 	| placeless_element
62604ac863bSchristos 		{
62704ac863bSchristos 		  $$.obj = 0;
62804ac863bSchristos 		  $$.x = current_position.x;
62904ac863bSchristos 		  $$.y = current_position.y;
63004ac863bSchristos 		}
63104ac863bSchristos 	;
63204ac863bSchristos 
63304ac863bSchristos optional_element:
63404ac863bSchristos 	/* empty */
63504ac863bSchristos 		{}
63604ac863bSchristos 	| element
63704ac863bSchristos 		{}
63804ac863bSchristos 	;
63904ac863bSchristos 
64004ac863bSchristos object_spec:
64104ac863bSchristos 	BOX
64204ac863bSchristos 		{ $$ = new object_spec(BOX_OBJECT); }
64304ac863bSchristos 	| CIRCLE
64404ac863bSchristos 		{ $$ = new object_spec(CIRCLE_OBJECT); }
64504ac863bSchristos 	| ELLIPSE
64604ac863bSchristos 		{ $$ = new object_spec(ELLIPSE_OBJECT); }
64704ac863bSchristos 	| ARC
64804ac863bSchristos 		{
64904ac863bSchristos 		  $$ = new object_spec(ARC_OBJECT);
65004ac863bSchristos 		  $$->dir = current_direction;
65104ac863bSchristos 		}
65204ac863bSchristos 	| LINE
65304ac863bSchristos 		{
65404ac863bSchristos 		  $$ = new object_spec(LINE_OBJECT);
65504ac863bSchristos 		  lookup_variable("lineht", & $$->segment_height);
65604ac863bSchristos 		  lookup_variable("linewid", & $$->segment_width);
65704ac863bSchristos 		  $$->dir = current_direction;
65804ac863bSchristos 		}
65904ac863bSchristos 	| ARROW
66004ac863bSchristos 		{
66104ac863bSchristos 		  $$ = new object_spec(ARROW_OBJECT);
66204ac863bSchristos 		  lookup_variable("lineht", & $$->segment_height);
66304ac863bSchristos 		  lookup_variable("linewid", & $$->segment_width);
66404ac863bSchristos 		  $$->dir = current_direction;
66504ac863bSchristos 		}
66604ac863bSchristos 	| MOVE
66704ac863bSchristos 		{
66804ac863bSchristos 		  $$ = new object_spec(MOVE_OBJECT);
66904ac863bSchristos 		  lookup_variable("moveht", & $$->segment_height);
67004ac863bSchristos 		  lookup_variable("movewid", & $$->segment_width);
67104ac863bSchristos 		  $$->dir = current_direction;
67204ac863bSchristos 		}
67304ac863bSchristos 	| SPLINE
67404ac863bSchristos 		{
67504ac863bSchristos 		  $$ = new object_spec(SPLINE_OBJECT);
67604ac863bSchristos 		  lookup_variable("lineht", & $$->segment_height);
67704ac863bSchristos 		  lookup_variable("linewid", & $$->segment_width);
67804ac863bSchristos 		  $$->dir = current_direction;
67904ac863bSchristos 		}
68004ac863bSchristos 	| text							%prec TEXT
68104ac863bSchristos 		{
68204ac863bSchristos 		  $$ = new object_spec(TEXT_OBJECT);
68304ac863bSchristos 		  $$->text = new text_item($1.str, $1.filename, $1.lineno);
68404ac863bSchristos 		}
68504ac863bSchristos 	| PLOT expr
68604ac863bSchristos 		{
68704ac863bSchristos 		  $$ = new object_spec(TEXT_OBJECT);
68804ac863bSchristos 		  $$->text = new text_item(format_number(0, $2), 0, -1);
68904ac863bSchristos 		}
69004ac863bSchristos 	| PLOT expr text
69104ac863bSchristos 		{
69204ac863bSchristos 		  $$ = new object_spec(TEXT_OBJECT);
69304ac863bSchristos 		  $$->text = new text_item(format_number($3.str, $2),
69404ac863bSchristos 					   $3.filename, $3.lineno);
69504ac863bSchristos 		  a_delete $3.str;
69604ac863bSchristos 		}
69704ac863bSchristos 	| '['
69804ac863bSchristos 		{
69904ac863bSchristos 		  saved_state *p = new saved_state;
70004ac863bSchristos 		  $<pstate>$ = p;
70104ac863bSchristos 		  p->x = current_position.x;
70204ac863bSchristos 		  p->y = current_position.y;
70304ac863bSchristos 		  p->dir = current_direction;
70404ac863bSchristos 		  p->tbl = current_table;
70504ac863bSchristos 		  p->prev = current_saved_state;
70604ac863bSchristos 		  current_position.x = 0.0;
70704ac863bSchristos 		  current_position.y = 0.0;
70804ac863bSchristos 		  current_table = new PTABLE(place);
70904ac863bSchristos 		  current_saved_state = p;
71004ac863bSchristos 		  olist.append(make_mark_object());
71104ac863bSchristos 		}
71204ac863bSchristos 	  element_list ']'
71304ac863bSchristos 		{
71404ac863bSchristos 		  current_position.x = $<pstate>2->x;
71504ac863bSchristos 		  current_position.y = $<pstate>2->y;
71604ac863bSchristos 		  current_direction = $<pstate>2->dir;
71704ac863bSchristos 		  $$ = new object_spec(BLOCK_OBJECT);
71804ac863bSchristos 		  olist.wrap_up_block(& $$->oblist);
71904ac863bSchristos 		  $$->tbl = current_table;
72004ac863bSchristos 		  current_table = $<pstate>2->tbl;
72104ac863bSchristos 		  current_saved_state = $<pstate>2->prev;
72204ac863bSchristos 		  delete $<pstate>2;
72304ac863bSchristos 		}
72404ac863bSchristos 	| object_spec HEIGHT expr
72504ac863bSchristos 		{
72604ac863bSchristos 		  $$ = $1;
72704ac863bSchristos 		  $$->height = $3;
72804ac863bSchristos 		  $$->flags |= HAS_HEIGHT;
72904ac863bSchristos 		}
73004ac863bSchristos 	| object_spec RADIUS expr
73104ac863bSchristos 		{
73204ac863bSchristos 		  $$ = $1;
73304ac863bSchristos 		  $$->radius = $3;
73404ac863bSchristos 		  $$->flags |= HAS_RADIUS;
73504ac863bSchristos 		}
73604ac863bSchristos 	| object_spec WIDTH expr
73704ac863bSchristos 		{
73804ac863bSchristos 		  $$ = $1;
73904ac863bSchristos 		  $$->width = $3;
74004ac863bSchristos 		  $$->flags |= HAS_WIDTH;
74104ac863bSchristos 		}
74204ac863bSchristos 	| object_spec DIAMETER expr
74304ac863bSchristos 		{
74404ac863bSchristos 		  $$ = $1;
74504ac863bSchristos 		  $$->radius = $3/2.0;
74604ac863bSchristos 		  $$->flags |= HAS_RADIUS;
74704ac863bSchristos 		}
74804ac863bSchristos 	| object_spec expr					%prec HEIGHT
74904ac863bSchristos 		{
75004ac863bSchristos 		  $$ = $1;
75104ac863bSchristos 		  $$->flags |= HAS_SEGMENT;
75204ac863bSchristos 		  switch ($$->dir) {
75304ac863bSchristos 		  case UP_DIRECTION:
75404ac863bSchristos 		    $$->segment_pos.y += $2;
75504ac863bSchristos 		    break;
75604ac863bSchristos 		  case DOWN_DIRECTION:
75704ac863bSchristos 		    $$->segment_pos.y -= $2;
75804ac863bSchristos 		    break;
75904ac863bSchristos 		  case RIGHT_DIRECTION:
76004ac863bSchristos 		    $$->segment_pos.x += $2;
76104ac863bSchristos 		    break;
76204ac863bSchristos 		  case LEFT_DIRECTION:
76304ac863bSchristos 		    $$->segment_pos.x -= $2;
76404ac863bSchristos 		    break;
76504ac863bSchristos 		  }
76604ac863bSchristos 		}
76704ac863bSchristos 	| object_spec UP
76804ac863bSchristos 		{
76904ac863bSchristos 		  $$ = $1;
77004ac863bSchristos 		  $$->dir = UP_DIRECTION;
77104ac863bSchristos 		  $$->flags |= HAS_SEGMENT;
77204ac863bSchristos 		  $$->segment_pos.y += $$->segment_height;
77304ac863bSchristos 		}
77404ac863bSchristos 	| object_spec UP expr
77504ac863bSchristos 		{
77604ac863bSchristos 		  $$ = $1;
77704ac863bSchristos 		  $$->dir = UP_DIRECTION;
77804ac863bSchristos 		  $$->flags |= HAS_SEGMENT;
77904ac863bSchristos 		  $$->segment_pos.y += $3;
78004ac863bSchristos 		}
78104ac863bSchristos 	| object_spec DOWN
78204ac863bSchristos 		{
78304ac863bSchristos 		  $$ = $1;
78404ac863bSchristos 		  $$->dir = DOWN_DIRECTION;
78504ac863bSchristos 		  $$->flags |= HAS_SEGMENT;
78604ac863bSchristos 		  $$->segment_pos.y -= $$->segment_height;
78704ac863bSchristos 		}
78804ac863bSchristos 	| object_spec DOWN expr
78904ac863bSchristos 		{
79004ac863bSchristos 		  $$ = $1;
79104ac863bSchristos 		  $$->dir = DOWN_DIRECTION;
79204ac863bSchristos 		  $$->flags |= HAS_SEGMENT;
79304ac863bSchristos 		  $$->segment_pos.y -= $3;
79404ac863bSchristos 		}
79504ac863bSchristos 	| object_spec RIGHT
79604ac863bSchristos 		{
79704ac863bSchristos 		  $$ = $1;
79804ac863bSchristos 		  $$->dir = RIGHT_DIRECTION;
79904ac863bSchristos 		  $$->flags |= HAS_SEGMENT;
80004ac863bSchristos 		  $$->segment_pos.x += $$->segment_width;
80104ac863bSchristos 		}
80204ac863bSchristos 	| object_spec RIGHT expr
80304ac863bSchristos 		{
80404ac863bSchristos 		  $$ = $1;
80504ac863bSchristos 		  $$->dir = RIGHT_DIRECTION;
80604ac863bSchristos 		  $$->flags |= HAS_SEGMENT;
80704ac863bSchristos 		  $$->segment_pos.x += $3;
80804ac863bSchristos 		}
80904ac863bSchristos 	| object_spec LEFT
81004ac863bSchristos 		{
81104ac863bSchristos 		  $$ = $1;
81204ac863bSchristos 		  $$->dir = LEFT_DIRECTION;
81304ac863bSchristos 		  $$->flags |= HAS_SEGMENT;
81404ac863bSchristos 		  $$->segment_pos.x -= $$->segment_width;
81504ac863bSchristos 		}
81604ac863bSchristos 	| object_spec LEFT expr
81704ac863bSchristos 		{
81804ac863bSchristos 		  $$ = $1;
81904ac863bSchristos 		  $$->dir = LEFT_DIRECTION;
82004ac863bSchristos 		  $$->flags |= HAS_SEGMENT;
82104ac863bSchristos 		  $$->segment_pos.x -= $3;
82204ac863bSchristos 		}
82304ac863bSchristos 	| object_spec FROM position
82404ac863bSchristos 		{
82504ac863bSchristos 		  $$ = $1;
82604ac863bSchristos 		  $$->flags |= HAS_FROM;
82704ac863bSchristos 		  $$->from.x = $3.x;
82804ac863bSchristos 		  $$->from.y = $3.y;
82904ac863bSchristos 		}
83004ac863bSchristos 	| object_spec TO position
83104ac863bSchristos 		{
83204ac863bSchristos 		  $$ = $1;
83304ac863bSchristos 		  if ($$->flags & HAS_SEGMENT)
83404ac863bSchristos 		    $$->segment_list = new segment($$->segment_pos,
83504ac863bSchristos 						   $$->segment_is_absolute,
83604ac863bSchristos 						   $$->segment_list);
83704ac863bSchristos 		  $$->flags |= HAS_SEGMENT;
83804ac863bSchristos 		  $$->segment_pos.x = $3.x;
83904ac863bSchristos 		  $$->segment_pos.y = $3.y;
84004ac863bSchristos 		  $$->segment_is_absolute = 1;
84104ac863bSchristos 		  $$->flags |= HAS_TO;
84204ac863bSchristos 		  $$->to.x = $3.x;
84304ac863bSchristos 		  $$->to.y = $3.y;
84404ac863bSchristos 		}
84504ac863bSchristos 	| object_spec AT position
84604ac863bSchristos 		{
84704ac863bSchristos 		  $$ = $1;
84804ac863bSchristos 		  $$->flags |= HAS_AT;
84904ac863bSchristos 		  $$->at.x = $3.x;
85004ac863bSchristos 		  $$->at.y = $3.y;
85104ac863bSchristos 		  if ($$->type != ARC_OBJECT) {
85204ac863bSchristos 		    $$->flags |= HAS_FROM;
85304ac863bSchristos 		    $$->from.x = $3.x;
85404ac863bSchristos 		    $$->from.y = $3.y;
85504ac863bSchristos 		  }
85604ac863bSchristos 		}
85704ac863bSchristos 	| object_spec WITH path
85804ac863bSchristos 		{
85904ac863bSchristos 		  $$ = $1;
86004ac863bSchristos 		  $$->flags |= HAS_WITH;
86104ac863bSchristos 		  $$->with = $3;
86204ac863bSchristos 		}
86304ac863bSchristos 	| object_spec WITH position				%prec ','
86404ac863bSchristos 		{
86504ac863bSchristos 		  $$ = $1;
86604ac863bSchristos 		  $$->flags |= HAS_WITH;
86704ac863bSchristos 		  position pos;
86804ac863bSchristos 		  pos.x = $3.x;
86904ac863bSchristos 		  pos.y = $3.y;
87004ac863bSchristos 		  $$->with = new path(pos);
87104ac863bSchristos 		}
87204ac863bSchristos 	| object_spec BY expr_pair
87304ac863bSchristos 		{
87404ac863bSchristos 		  $$ = $1;
87504ac863bSchristos 		  $$->flags |= HAS_SEGMENT;
87604ac863bSchristos 		  $$->segment_pos.x += $3.x;
87704ac863bSchristos 		  $$->segment_pos.y += $3.y;
87804ac863bSchristos 		}
87904ac863bSchristos 	| object_spec THEN
88004ac863bSchristos   		{
88104ac863bSchristos 		  $$ = $1;
88204ac863bSchristos 		  if ($$->flags & HAS_SEGMENT) {
88304ac863bSchristos 		    $$->segment_list = new segment($$->segment_pos,
88404ac863bSchristos 						   $$->segment_is_absolute,
88504ac863bSchristos 						   $$->segment_list);
88604ac863bSchristos 		    $$->flags &= ~HAS_SEGMENT;
88704ac863bSchristos 		    $$->segment_pos.x = $$->segment_pos.y = 0.0;
88804ac863bSchristos 		    $$->segment_is_absolute = 0;
88904ac863bSchristos 		  }
89004ac863bSchristos 		}
89104ac863bSchristos 	| object_spec SOLID
89204ac863bSchristos 		{
89304ac863bSchristos 		  $$ = $1;	// nothing
89404ac863bSchristos 		}
89504ac863bSchristos 	| object_spec DOTTED
89604ac863bSchristos 		{
89704ac863bSchristos 		  $$ = $1;
89804ac863bSchristos 		  $$->flags |= IS_DOTTED;
89904ac863bSchristos 		  lookup_variable("dashwid", & $$->dash_width);
90004ac863bSchristos 		}
90104ac863bSchristos 	| object_spec DOTTED expr
90204ac863bSchristos 		{
90304ac863bSchristos 		  $$ = $1;
90404ac863bSchristos 		  $$->flags |= IS_DOTTED;
90504ac863bSchristos 		  $$->dash_width = $3;
90604ac863bSchristos 		}
90704ac863bSchristos 	| object_spec DASHED
90804ac863bSchristos 		{
90904ac863bSchristos 		  $$ = $1;
91004ac863bSchristos 		  $$->flags |= IS_DASHED;
91104ac863bSchristos 		  lookup_variable("dashwid", & $$->dash_width);
91204ac863bSchristos 		}
91304ac863bSchristos 	| object_spec DASHED expr
91404ac863bSchristos 		{
91504ac863bSchristos 		  $$ = $1;
91604ac863bSchristos 		  $$->flags |= IS_DASHED;
91704ac863bSchristos 		  $$->dash_width = $3;
91804ac863bSchristos 		}
91904ac863bSchristos 	| object_spec FILL
92004ac863bSchristos 		{
92104ac863bSchristos 		  $$ = $1;
92204ac863bSchristos 		  $$->flags |= IS_DEFAULT_FILLED;
92304ac863bSchristos 		}
92404ac863bSchristos 	| object_spec FILL expr
92504ac863bSchristos 		{
92604ac863bSchristos 		  $$ = $1;
92704ac863bSchristos 		  $$->flags |= IS_FILLED;
92804ac863bSchristos 		  $$->fill = $3;
92904ac863bSchristos 		}
93004ac863bSchristos 	| object_spec SHADED text
93104ac863bSchristos 		{
93204ac863bSchristos 		  $$ = $1;
93304ac863bSchristos 		  $$->flags |= (IS_SHADED | IS_FILLED);
93404ac863bSchristos 		  $$->shaded = new char[strlen($3.str)+1];
93504ac863bSchristos 		  strcpy($$->shaded, $3.str);
93604ac863bSchristos 		}
93704ac863bSchristos 	| object_spec COLORED text
93804ac863bSchristos 		{
93904ac863bSchristos 		  $$ = $1;
94004ac863bSchristos 		  $$->flags |= (IS_SHADED | IS_OUTLINED | IS_FILLED);
94104ac863bSchristos 		  $$->shaded = new char[strlen($3.str)+1];
94204ac863bSchristos 		  strcpy($$->shaded, $3.str);
94304ac863bSchristos 		  $$->outlined = new char[strlen($3.str)+1];
94404ac863bSchristos 		  strcpy($$->outlined, $3.str);
94504ac863bSchristos 		}
94604ac863bSchristos 	| object_spec OUTLINED text
94704ac863bSchristos 		{
94804ac863bSchristos 		  $$ = $1;
94904ac863bSchristos 		  $$->flags |= IS_OUTLINED;
95004ac863bSchristos 		  $$->outlined = new char[strlen($3.str)+1];
95104ac863bSchristos 		  strcpy($$->outlined, $3.str);
95204ac863bSchristos 		}
95304ac863bSchristos 	| object_spec CHOP
95404ac863bSchristos   		{
95504ac863bSchristos 		  $$ = $1;
95604ac863bSchristos 		  // line chop chop means line chop 0 chop 0
95704ac863bSchristos 		  if ($$->flags & IS_DEFAULT_CHOPPED) {
95804ac863bSchristos 		    $$->flags |= IS_CHOPPED;
95904ac863bSchristos 		    $$->flags &= ~IS_DEFAULT_CHOPPED;
96004ac863bSchristos 		    $$->start_chop = $$->end_chop = 0.0;
96104ac863bSchristos 		  }
96204ac863bSchristos 		  else if ($$->flags & IS_CHOPPED) {
96304ac863bSchristos 		    $$->end_chop = 0.0;
96404ac863bSchristos 		  }
96504ac863bSchristos 		  else {
96604ac863bSchristos 		    $$->flags |= IS_DEFAULT_CHOPPED;
96704ac863bSchristos 		  }
96804ac863bSchristos 		}
96904ac863bSchristos 	| object_spec CHOP expr
97004ac863bSchristos 		{
97104ac863bSchristos 		  $$ = $1;
97204ac863bSchristos 		  if ($$->flags & IS_DEFAULT_CHOPPED) {
97304ac863bSchristos 		    $$->flags |= IS_CHOPPED;
97404ac863bSchristos 		    $$->flags &= ~IS_DEFAULT_CHOPPED;
97504ac863bSchristos 		    $$->start_chop = 0.0;
97604ac863bSchristos 		    $$->end_chop = $3;
97704ac863bSchristos 		  }
97804ac863bSchristos 		  else if ($$->flags & IS_CHOPPED) {
97904ac863bSchristos 		    $$->end_chop = $3;
98004ac863bSchristos 		  }
98104ac863bSchristos 		  else {
98204ac863bSchristos 		    $$->start_chop = $$->end_chop = $3;
98304ac863bSchristos 		    $$->flags |= IS_CHOPPED;
98404ac863bSchristos 		  }
98504ac863bSchristos 		}
98604ac863bSchristos 	| object_spec SAME
98704ac863bSchristos 		{
98804ac863bSchristos 		  $$ = $1;
98904ac863bSchristos 		  $$->flags |= IS_SAME;
99004ac863bSchristos 		}
99104ac863bSchristos 	| object_spec INVISIBLE
99204ac863bSchristos 		{
99304ac863bSchristos 		  $$ = $1;
99404ac863bSchristos 		  $$->flags |= IS_INVISIBLE;
99504ac863bSchristos 		}
99604ac863bSchristos 	| object_spec LEFT_ARROW_HEAD
99704ac863bSchristos 		{
99804ac863bSchristos 		  $$ = $1;
99904ac863bSchristos 		  $$->flags |= HAS_LEFT_ARROW_HEAD;
100004ac863bSchristos 		}
100104ac863bSchristos 	| object_spec RIGHT_ARROW_HEAD
100204ac863bSchristos 		{
100304ac863bSchristos 		  $$ = $1;
100404ac863bSchristos 		  $$->flags |= HAS_RIGHT_ARROW_HEAD;
100504ac863bSchristos 		}
100604ac863bSchristos 	| object_spec DOUBLE_ARROW_HEAD
100704ac863bSchristos 		{
100804ac863bSchristos 		  $$ = $1;
100904ac863bSchristos 		  $$->flags |= (HAS_LEFT_ARROW_HEAD|HAS_RIGHT_ARROW_HEAD);
101004ac863bSchristos 		}
101104ac863bSchristos 	| object_spec CW
101204ac863bSchristos 		{
101304ac863bSchristos 		  $$ = $1;
101404ac863bSchristos 		  $$->flags |= IS_CLOCKWISE;
101504ac863bSchristos 		}
101604ac863bSchristos 	| object_spec CCW
101704ac863bSchristos 		{
101804ac863bSchristos 		  $$ = $1;
101904ac863bSchristos 		  $$->flags &= ~IS_CLOCKWISE;
102004ac863bSchristos 		}
102104ac863bSchristos 	| object_spec text					%prec TEXT
102204ac863bSchristos 		{
102304ac863bSchristos 		  $$ = $1;
102404ac863bSchristos 		  text_item **p;
102504ac863bSchristos 		  for (p = & $$->text; *p; p = &(*p)->next)
102604ac863bSchristos 		    ;
102704ac863bSchristos 		  *p = new text_item($2.str, $2.filename, $2.lineno);
102804ac863bSchristos 		}
102904ac863bSchristos 	| object_spec LJUST
103004ac863bSchristos 		{
103104ac863bSchristos 		  $$ = $1;
103204ac863bSchristos 		  if ($$->text) {
103304ac863bSchristos 		    text_item *p;
103404ac863bSchristos 		    for (p = $$->text; p->next; p = p->next)
103504ac863bSchristos 		      ;
103604ac863bSchristos 		    p->adj.h = LEFT_ADJUST;
103704ac863bSchristos 		  }
103804ac863bSchristos 		}
103904ac863bSchristos 	| object_spec RJUST
104004ac863bSchristos 		{
104104ac863bSchristos 		  $$ = $1;
104204ac863bSchristos 		  if ($$->text) {
104304ac863bSchristos 		    text_item *p;
104404ac863bSchristos 		    for (p = $$->text; p->next; p = p->next)
104504ac863bSchristos 		      ;
104604ac863bSchristos 		    p->adj.h = RIGHT_ADJUST;
104704ac863bSchristos 		  }
104804ac863bSchristos 		}
104904ac863bSchristos 	| object_spec ABOVE
105004ac863bSchristos 		{
105104ac863bSchristos 		  $$ = $1;
105204ac863bSchristos 		  if ($$->text) {
105304ac863bSchristos 		    text_item *p;
105404ac863bSchristos 		    for (p = $$->text; p->next; p = p->next)
105504ac863bSchristos 		      ;
105604ac863bSchristos 		    p->adj.v = ABOVE_ADJUST;
105704ac863bSchristos 		  }
105804ac863bSchristos 		}
105904ac863bSchristos 	| object_spec BELOW
106004ac863bSchristos 		{
106104ac863bSchristos 		  $$ = $1;
106204ac863bSchristos 		  if ($$->text) {
106304ac863bSchristos 		    text_item *p;
106404ac863bSchristos 		    for (p = $$->text; p->next; p = p->next)
106504ac863bSchristos 		      ;
106604ac863bSchristos 		    p->adj.v = BELOW_ADJUST;
106704ac863bSchristos 		  }
106804ac863bSchristos 		}
106904ac863bSchristos 	| object_spec THICKNESS expr
107004ac863bSchristos 		{
107104ac863bSchristos 		  $$ = $1;
107204ac863bSchristos 		  $$->flags |= HAS_THICKNESS;
107304ac863bSchristos 		  $$->thickness = $3;
107404ac863bSchristos 		}
107504ac863bSchristos 	| object_spec ALIGNED
107604ac863bSchristos 		{
107704ac863bSchristos 		  $$ = $1;
107804ac863bSchristos 		  $$->flags |= IS_ALIGNED;
107904ac863bSchristos 		}
108004ac863bSchristos 	;
108104ac863bSchristos 
108204ac863bSchristos text:
108304ac863bSchristos 	TEXT
108404ac863bSchristos 		{ $$ = $1; }
108504ac863bSchristos 	| SPRINTF '(' TEXT sprintf_args ')'
108604ac863bSchristos 		{
108704ac863bSchristos 		  $$.filename = $3.filename;
108804ac863bSchristos 		  $$.lineno = $3.lineno;
108904ac863bSchristos 		  $$.str = do_sprintf($3.str, $4.v, $4.nv);
109004ac863bSchristos 		  a_delete $4.v;
109104ac863bSchristos 		  a_delete $3.str;
109204ac863bSchristos 		}
109304ac863bSchristos 	;
109404ac863bSchristos 
109504ac863bSchristos sprintf_args:
109604ac863bSchristos 	/* empty */
109704ac863bSchristos 		{
109804ac863bSchristos 		  $$.v = 0;
109904ac863bSchristos 		  $$.nv = 0;
110004ac863bSchristos 		  $$.maxv = 0;
110104ac863bSchristos 		}
110204ac863bSchristos 	| sprintf_args ',' expr
110304ac863bSchristos 		{
110404ac863bSchristos 		  $$ = $1;
110504ac863bSchristos 		  if ($$.nv >= $$.maxv) {
110604ac863bSchristos 		    if ($$.nv == 0) {
110704ac863bSchristos 		      $$.v = new double[4];
110804ac863bSchristos 		      $$.maxv = 4;
110904ac863bSchristos 		    }
111004ac863bSchristos 		    else {
111104ac863bSchristos 		      double *oldv = $$.v;
111204ac863bSchristos 		      $$.maxv *= 2;
111304ac863bSchristos #if 0
111404ac863bSchristos 		      $$.v = new double[$$.maxv];
111504ac863bSchristos 		      memcpy($$.v, oldv, $$.nv*sizeof(double));
111604ac863bSchristos #else
111704ac863bSchristos 		      // workaround for bug in Compaq C++ V6.5-033
111804ac863bSchristos 		      // for Compaq Tru64 UNIX V5.1A (Rev. 1885)
111904ac863bSchristos 		      double *foo = new double[$$.maxv];
112004ac863bSchristos 		      memcpy(foo, oldv, $$.nv*sizeof(double));
112104ac863bSchristos 		      $$.v = foo;
112204ac863bSchristos #endif
112304ac863bSchristos 		      a_delete oldv;
112404ac863bSchristos 		    }
112504ac863bSchristos 		  }
112604ac863bSchristos 		  $$.v[$$.nv] = $3;
112704ac863bSchristos 		  $$.nv += 1;
112804ac863bSchristos 		}
112904ac863bSchristos 	;
113004ac863bSchristos 
113104ac863bSchristos position:
113204ac863bSchristos   	position_not_place
113304ac863bSchristos 		{ $$ = $1; }
113404ac863bSchristos 	| place
113504ac863bSchristos   		{
113604ac863bSchristos 		  position pos = $1;
113704ac863bSchristos 		  $$.x = pos.x;
113804ac863bSchristos 		  $$.y = pos.y;
113904ac863bSchristos 		}
114004ac863bSchristos 	| '(' place ')'
114104ac863bSchristos 		{
114204ac863bSchristos 		  position pos = $2;
114304ac863bSchristos 		  $$.x = pos.x;
114404ac863bSchristos 		  $$.y = pos.y;
114504ac863bSchristos 		}
114604ac863bSchristos 	;
114704ac863bSchristos 
114804ac863bSchristos position_not_place:
114904ac863bSchristos 	expr_pair
115004ac863bSchristos 		{ $$ = $1; }
115104ac863bSchristos 	| position '+' expr_pair
115204ac863bSchristos 		{
115304ac863bSchristos 		  $$.x = $1.x + $3.x;
115404ac863bSchristos 		  $$.y = $1.y + $3.y;
115504ac863bSchristos 		}
115604ac863bSchristos 	| '(' position '+' expr_pair ')'
115704ac863bSchristos 		{
115804ac863bSchristos 		  $$.x = $2.x + $4.x;
115904ac863bSchristos 		  $$.y = $2.y + $4.y;
116004ac863bSchristos 		}
116104ac863bSchristos 	| position '-' expr_pair
116204ac863bSchristos 		{
116304ac863bSchristos 		  $$.x = $1.x - $3.x;
116404ac863bSchristos 		  $$.y = $1.y - $3.y;
116504ac863bSchristos 		}
116604ac863bSchristos 	| '(' position '-' expr_pair ')'
116704ac863bSchristos 		{
116804ac863bSchristos 		  $$.x = $2.x - $4.x;
116904ac863bSchristos 		  $$.y = $2.y - $4.y;
117004ac863bSchristos 		}
117104ac863bSchristos 	| '(' position ',' position ')'
117204ac863bSchristos 		{
117304ac863bSchristos 		  $$.x = $2.x;
117404ac863bSchristos 		  $$.y = $4.y;
117504ac863bSchristos 		}
117604ac863bSchristos 	| expr between position AND position
117704ac863bSchristos 		{
117804ac863bSchristos 		  $$.x = (1.0 - $1)*$3.x + $1*$5.x;
117904ac863bSchristos 		  $$.y = (1.0 - $1)*$3.y + $1*$5.y;
118004ac863bSchristos 		}
118104ac863bSchristos 	| '(' expr between position AND position ')'
118204ac863bSchristos 		{
118304ac863bSchristos 		  $$.x = (1.0 - $2)*$4.x + $2*$6.x;
118404ac863bSchristos 		  $$.y = (1.0 - $2)*$4.y + $2*$6.y;
118504ac863bSchristos 		}
118604ac863bSchristos 	| expr '<' position ',' position '>'
118704ac863bSchristos 		{
118804ac863bSchristos 		  $$.x = (1.0 - $1)*$3.x + $1*$5.x;
118904ac863bSchristos 		  $$.y = (1.0 - $1)*$3.y + $1*$5.y;
119004ac863bSchristos 		}
119104ac863bSchristos 	| '(' expr '<' position ',' position '>' ')'
119204ac863bSchristos 		{
119304ac863bSchristos 		  $$.x = (1.0 - $2)*$4.x + $2*$6.x;
119404ac863bSchristos 		  $$.y = (1.0 - $2)*$4.y + $2*$6.y;
119504ac863bSchristos 		}
119604ac863bSchristos 	;
119704ac863bSchristos 
119804ac863bSchristos between:
119904ac863bSchristos 	BETWEEN
120004ac863bSchristos 	| OF THE WAY BETWEEN
120104ac863bSchristos 	;
120204ac863bSchristos 
120304ac863bSchristos expr_pair:
120404ac863bSchristos 	expr ',' expr
120504ac863bSchristos 		{
120604ac863bSchristos 		  $$.x = $1;
120704ac863bSchristos 		  $$.y = $3;
120804ac863bSchristos 		}
120904ac863bSchristos 	| '(' expr_pair ')'
121004ac863bSchristos 		{ $$ = $2; }
121104ac863bSchristos 	;
121204ac863bSchristos 
121304ac863bSchristos place:
121404ac863bSchristos 	/* line at A left == line (at A) left */
121504ac863bSchristos 	label							%prec CHOP
121604ac863bSchristos 		{ $$ = $1; }
121704ac863bSchristos 	| label corner
121804ac863bSchristos 		{
121904ac863bSchristos 		  path pth($2);
122004ac863bSchristos 		  if (!pth.follow($1, & $$))
122104ac863bSchristos 		    YYABORT;
122204ac863bSchristos 		}
122304ac863bSchristos 	| corner label
122404ac863bSchristos 		{
122504ac863bSchristos 		  path pth($1);
122604ac863bSchristos 		  if (!pth.follow($2, & $$))
122704ac863bSchristos 		    YYABORT;
122804ac863bSchristos 		}
122904ac863bSchristos 	| corner OF label
123004ac863bSchristos 		{
123104ac863bSchristos 		  path pth($1);
123204ac863bSchristos 		  if (!pth.follow($3, & $$))
123304ac863bSchristos 		    YYABORT;
123404ac863bSchristos 		}
123504ac863bSchristos 	| HERE
123604ac863bSchristos 		{
123704ac863bSchristos 		  $$.x = current_position.x;
123804ac863bSchristos 		  $$.y = current_position.y;
123904ac863bSchristos 		  $$.obj = 0;
124004ac863bSchristos 		}
124104ac863bSchristos 	;
124204ac863bSchristos 
124304ac863bSchristos label:
124404ac863bSchristos 	LABEL
124504ac863bSchristos 		{
124604ac863bSchristos 		  place *p = lookup_label($1);
124704ac863bSchristos 		  if (!p) {
124804ac863bSchristos 		    lex_error("there is no place `%1'", $1);
124904ac863bSchristos 		    YYABORT;
125004ac863bSchristos 		  }
125104ac863bSchristos 		  $$ = *p;
125204ac863bSchristos 		  a_delete $1;
125304ac863bSchristos 		}
125404ac863bSchristos 	| nth_primitive
125504ac863bSchristos 		{ $$.obj = $1; }
125604ac863bSchristos 	| label '.' LABEL
125704ac863bSchristos 		{
125804ac863bSchristos 		  path pth($3);
125904ac863bSchristos 		  if (!pth.follow($1, & $$))
126004ac863bSchristos 		    YYABORT;
126104ac863bSchristos 		}
126204ac863bSchristos 	;
126304ac863bSchristos 
126404ac863bSchristos ordinal:
126504ac863bSchristos 	ORDINAL
126604ac863bSchristos 		{ $$ = $1; }
126704ac863bSchristos 	| '`' any_expr TH
126804ac863bSchristos 		{
126904ac863bSchristos 		  // XXX Check for overflow (and non-integers?).
127004ac863bSchristos 		  $$ = (int)$2;
127104ac863bSchristos 		}
127204ac863bSchristos 	;
127304ac863bSchristos 
127404ac863bSchristos optional_ordinal_last:
127504ac863bSchristos 	LAST
127604ac863bSchristos 		{ $$ = 1; }
127704ac863bSchristos   	| ordinal LAST
127804ac863bSchristos 		{ $$ = $1; }
127904ac863bSchristos 	;
128004ac863bSchristos 
128104ac863bSchristos nth_primitive:
128204ac863bSchristos 	ordinal object_type
128304ac863bSchristos 		{
128404ac863bSchristos 		  int count = 0;
128504ac863bSchristos 		  object *p;
128604ac863bSchristos 		  for (p = olist.head; p != 0; p = p->next)
128704ac863bSchristos 		    if (p->type() == $2 && ++count == $1) {
128804ac863bSchristos 		      $$ = p;
128904ac863bSchristos 		      break;
129004ac863bSchristos 		    }
129104ac863bSchristos 		  if (p == 0) {
129204ac863bSchristos 		    lex_error("there is no %1%2 %3", $1, ordinal_postfix($1),
129304ac863bSchristos 			      object_type_name($2));
129404ac863bSchristos 		    YYABORT;
129504ac863bSchristos 		  }
129604ac863bSchristos 		}
129704ac863bSchristos 	| optional_ordinal_last object_type
129804ac863bSchristos 		{
129904ac863bSchristos 		  int count = 0;
130004ac863bSchristos 		  object *p;
130104ac863bSchristos 		  for (p = olist.tail; p != 0; p = p->prev)
130204ac863bSchristos 		    if (p->type() == $2 && ++count == $1) {
130304ac863bSchristos 		      $$ = p;
130404ac863bSchristos 		      break;
130504ac863bSchristos 		    }
130604ac863bSchristos 		  if (p == 0) {
130704ac863bSchristos 		    lex_error("there is no %1%2 last %3", $1,
130804ac863bSchristos 			      ordinal_postfix($1), object_type_name($2));
130904ac863bSchristos 		    YYABORT;
131004ac863bSchristos 		  }
131104ac863bSchristos 		}
131204ac863bSchristos 	;
131304ac863bSchristos 
131404ac863bSchristos object_type:
131504ac863bSchristos 	BOX
131604ac863bSchristos   		{ $$ = BOX_OBJECT; }
131704ac863bSchristos 	| CIRCLE
131804ac863bSchristos 		{ $$ = CIRCLE_OBJECT; }
131904ac863bSchristos 	| ELLIPSE
132004ac863bSchristos 		{ $$ = ELLIPSE_OBJECT; }
132104ac863bSchristos 	| ARC
132204ac863bSchristos 		{ $$ = ARC_OBJECT; }
132304ac863bSchristos 	| LINE
132404ac863bSchristos 		{ $$ = LINE_OBJECT; }
132504ac863bSchristos 	| ARROW
132604ac863bSchristos 		{ $$ = ARROW_OBJECT; }
132704ac863bSchristos 	| SPLINE
132804ac863bSchristos 		{ $$ = SPLINE_OBJECT; }
132904ac863bSchristos 	| '[' ']'
133004ac863bSchristos 		{ $$ = BLOCK_OBJECT; }
133104ac863bSchristos 	| TEXT
133204ac863bSchristos 		{ $$ = TEXT_OBJECT; }
133304ac863bSchristos 	;
133404ac863bSchristos 
133504ac863bSchristos label_path:
133604ac863bSchristos  	'.' LABEL
133704ac863bSchristos 		{ $$ = new path($2); }
133804ac863bSchristos 	| label_path '.' LABEL
133904ac863bSchristos 		{
134004ac863bSchristos 		  $$ = $1;
134104ac863bSchristos 		  $$->append($3);
134204ac863bSchristos 		}
134304ac863bSchristos 	;
134404ac863bSchristos 
134504ac863bSchristos relative_path:
134604ac863bSchristos 	corner							%prec CHOP
134704ac863bSchristos 		{ $$ = new path($1); }
134804ac863bSchristos 	/* give this a lower precedence than LEFT and RIGHT so that
134904ac863bSchristos 	   [A: box] with .A left == [A: box] with (.A left) */
135004ac863bSchristos   	| label_path						%prec TEXT
135104ac863bSchristos 		{ $$ = $1; }
135204ac863bSchristos 	| label_path corner
135304ac863bSchristos 		{
135404ac863bSchristos 		  $$ = $1;
135504ac863bSchristos 		  $$->append($2);
135604ac863bSchristos 		}
135704ac863bSchristos 	;
135804ac863bSchristos 
135904ac863bSchristos path:
136004ac863bSchristos 	relative_path
136104ac863bSchristos 		{ $$ = $1; }
136204ac863bSchristos 	| '(' relative_path ',' relative_path ')'
136304ac863bSchristos 		{
136404ac863bSchristos 		  $$ = $2;
136504ac863bSchristos 		  $$->set_ypath($4);
136604ac863bSchristos 		}
136704ac863bSchristos 	/* The rest of these rules are a compatibility sop. */
136804ac863bSchristos 	| ORDINAL LAST object_type relative_path
136904ac863bSchristos 		{
137004ac863bSchristos 		  lex_warning("`%1%2 last %3' in `with' argument ignored",
137104ac863bSchristos 			      $1, ordinal_postfix($1), object_type_name($3));
137204ac863bSchristos 		  $$ = $4;
137304ac863bSchristos 		}
137404ac863bSchristos 	| LAST object_type relative_path
137504ac863bSchristos 		{
137604ac863bSchristos 		  lex_warning("`last %1' in `with' argument ignored",
137704ac863bSchristos 			      object_type_name($2));
137804ac863bSchristos 		  $$ = $3;
137904ac863bSchristos 		}
138004ac863bSchristos 	| ORDINAL object_type relative_path
138104ac863bSchristos 		{
138204ac863bSchristos 		  lex_warning("`%1%2 %3' in `with' argument ignored",
138304ac863bSchristos 			      $1, ordinal_postfix($1), object_type_name($2));
138404ac863bSchristos 		  $$ = $3;
138504ac863bSchristos 		}
138604ac863bSchristos 	| LABEL relative_path
138704ac863bSchristos 		{
138804ac863bSchristos 		  lex_warning("initial `%1' in `with' argument ignored", $1);
138904ac863bSchristos 		  a_delete $1;
139004ac863bSchristos 		  $$ = $2;
139104ac863bSchristos 		}
139204ac863bSchristos 	;
139304ac863bSchristos 
139404ac863bSchristos corner:
139504ac863bSchristos 	DOT_N
139604ac863bSchristos 		{ $$ = &object::north; }
139704ac863bSchristos 	| DOT_E
139804ac863bSchristos 		{ $$ = &object::east; }
139904ac863bSchristos 	| DOT_W
140004ac863bSchristos 		{ $$ = &object::west; }
140104ac863bSchristos 	| DOT_S
140204ac863bSchristos 		{ $$ = &object::south; }
140304ac863bSchristos 	| DOT_NE
140404ac863bSchristos 		{ $$ = &object::north_east; }
140504ac863bSchristos 	| DOT_SE
140604ac863bSchristos 		{ $$ = &object:: south_east; }
140704ac863bSchristos 	| DOT_NW
140804ac863bSchristos 		{ $$ = &object::north_west; }
140904ac863bSchristos 	| DOT_SW
141004ac863bSchristos 		{ $$ = &object::south_west; }
141104ac863bSchristos 	| DOT_C
141204ac863bSchristos 		{ $$ = &object::center; }
141304ac863bSchristos 	| DOT_START
141404ac863bSchristos 		{ $$ = &object::start; }
141504ac863bSchristos 	| DOT_END
141604ac863bSchristos 		{ $$ = &object::end; }
141704ac863bSchristos   	| TOP
141804ac863bSchristos 		{ $$ = &object::north; }
141904ac863bSchristos 	| BOTTOM
142004ac863bSchristos 		{ $$ = &object::south; }
142104ac863bSchristos 	| LEFT
142204ac863bSchristos 		{ $$ = &object::west; }
142304ac863bSchristos 	| RIGHT
142404ac863bSchristos 		{ $$ = &object::east; }
142504ac863bSchristos 	| UPPER LEFT
142604ac863bSchristos 		{ $$ = &object::north_west; }
142704ac863bSchristos 	| LOWER LEFT
142804ac863bSchristos 		{ $$ = &object::south_west; }
142904ac863bSchristos 	| UPPER RIGHT
143004ac863bSchristos 		{ $$ = &object::north_east; }
143104ac863bSchristos 	| LOWER RIGHT
143204ac863bSchristos 		{ $$ = &object::south_east; }
143304ac863bSchristos 	| LEFT_CORNER
143404ac863bSchristos 		{ $$ = &object::west; }
143504ac863bSchristos 	| RIGHT_CORNER
143604ac863bSchristos 		{ $$ = &object::east; }
143704ac863bSchristos 	| UPPER LEFT_CORNER
143804ac863bSchristos 		{ $$ = &object::north_west; }
143904ac863bSchristos 	| LOWER LEFT_CORNER
144004ac863bSchristos 		{ $$ = &object::south_west; }
144104ac863bSchristos 	| UPPER RIGHT_CORNER
144204ac863bSchristos 		{ $$ = &object::north_east; }
144304ac863bSchristos 	| LOWER RIGHT_CORNER
144404ac863bSchristos 		{ $$ = &object::south_east; }
144504ac863bSchristos 	| NORTH
144604ac863bSchristos 		{ $$ = &object::north; }
144704ac863bSchristos 	| SOUTH
144804ac863bSchristos 		{ $$ = &object::south; }
144904ac863bSchristos 	| EAST
145004ac863bSchristos 		{ $$ = &object::east; }
145104ac863bSchristos 	| WEST
145204ac863bSchristos 		{ $$ = &object::west; }
145304ac863bSchristos 	| CENTER
145404ac863bSchristos 		{ $$ = &object::center; }
145504ac863bSchristos 	| START
145604ac863bSchristos 		{ $$ = &object::start; }
145704ac863bSchristos 	| END
145804ac863bSchristos 		{ $$ = &object::end; }
145904ac863bSchristos 	;
146004ac863bSchristos 
146104ac863bSchristos expr:
146204ac863bSchristos 	VARIABLE
146304ac863bSchristos 		{
146404ac863bSchristos 		  if (!lookup_variable($1, & $$)) {
146504ac863bSchristos 		    lex_error("there is no variable `%1'", $1);
146604ac863bSchristos 		    YYABORT;
146704ac863bSchristos 		  }
146804ac863bSchristos 		  a_delete $1;
146904ac863bSchristos 		}
147004ac863bSchristos 	| NUMBER
147104ac863bSchristos 		{ $$ = $1; }
147204ac863bSchristos 	| place DOT_X
147304ac863bSchristos   		{
147404ac863bSchristos 		  if ($1.obj != 0)
147504ac863bSchristos 		    $$ = $1.obj->origin().x;
147604ac863bSchristos 		  else
147704ac863bSchristos 		    $$ = $1.x;
147804ac863bSchristos 		}
147904ac863bSchristos 	| place DOT_Y
148004ac863bSchristos 		{
148104ac863bSchristos 		  if ($1.obj != 0)
148204ac863bSchristos 		    $$ = $1.obj->origin().y;
148304ac863bSchristos 		  else
148404ac863bSchristos 		    $$ = $1.y;
148504ac863bSchristos 		}
148604ac863bSchristos 	| place DOT_HT
148704ac863bSchristos 		{
148804ac863bSchristos 		  if ($1.obj != 0)
148904ac863bSchristos 		    $$ = $1.obj->height();
149004ac863bSchristos 		  else
149104ac863bSchristos 		    $$ = 0.0;
149204ac863bSchristos 		}
149304ac863bSchristos 	| place DOT_WID
149404ac863bSchristos 		{
149504ac863bSchristos 		  if ($1.obj != 0)
149604ac863bSchristos 		    $$ = $1.obj->width();
149704ac863bSchristos 		  else
149804ac863bSchristos 		    $$ = 0.0;
149904ac863bSchristos 		}
150004ac863bSchristos 	| place DOT_RAD
150104ac863bSchristos 		{
150204ac863bSchristos 		  if ($1.obj != 0)
150304ac863bSchristos 		    $$ = $1.obj->radius();
150404ac863bSchristos 		  else
150504ac863bSchristos 		    $$ = 0.0;
150604ac863bSchristos 		}
150704ac863bSchristos 	| expr '+' expr
150804ac863bSchristos 		{ $$ = $1 + $3; }
150904ac863bSchristos 	| expr '-' expr
151004ac863bSchristos 		{ $$ = $1 - $3; }
151104ac863bSchristos 	| expr '*' expr
151204ac863bSchristos 		{ $$ = $1 * $3; }
151304ac863bSchristos 	| expr '/' expr
151404ac863bSchristos 		{
151504ac863bSchristos 		  if ($3 == 0.0) {
151604ac863bSchristos 		    lex_error("division by zero");
151704ac863bSchristos 		    YYABORT;
151804ac863bSchristos 		  }
151904ac863bSchristos 		  $$ = $1/$3;
152004ac863bSchristos 		}
152104ac863bSchristos 	| expr '%' expr
152204ac863bSchristos 		{
152304ac863bSchristos 		  if ($3 == 0.0) {
152404ac863bSchristos 		    lex_error("modulus by zero");
152504ac863bSchristos 		    YYABORT;
152604ac863bSchristos 		  }
152704ac863bSchristos 		  $$ = fmod($1, $3);
152804ac863bSchristos 		}
152904ac863bSchristos 	| expr '^' expr
153004ac863bSchristos 		{
153104ac863bSchristos 		  errno = 0;
153204ac863bSchristos 		  $$ = pow($1, $3);
153304ac863bSchristos 		  if (errno == EDOM) {
153404ac863bSchristos 		    lex_error("arguments to `^' operator out of domain");
153504ac863bSchristos 		    YYABORT;
153604ac863bSchristos 		  }
153704ac863bSchristos 		  if (errno == ERANGE) {
153804ac863bSchristos 		    lex_error("result of `^' operator out of range");
153904ac863bSchristos 		    YYABORT;
154004ac863bSchristos 		  }
154104ac863bSchristos 		}
154204ac863bSchristos 	| '-' expr						%prec '!'
154304ac863bSchristos 		{ $$ = -$2; }
154404ac863bSchristos 	| '(' any_expr ')'
154504ac863bSchristos 		{ $$ = $2; }
154604ac863bSchristos 	| SIN '(' any_expr ')'
154704ac863bSchristos 		{
154804ac863bSchristos 		  errno = 0;
154904ac863bSchristos 		  $$ = sin($3);
155004ac863bSchristos 		  if (errno == ERANGE) {
155104ac863bSchristos 		    lex_error("sin result out of range");
155204ac863bSchristos 		    YYABORT;
155304ac863bSchristos 		  }
155404ac863bSchristos 		}
155504ac863bSchristos 	| COS '(' any_expr ')'
155604ac863bSchristos 		{
155704ac863bSchristos 		  errno = 0;
155804ac863bSchristos 		  $$ = cos($3);
155904ac863bSchristos 		  if (errno == ERANGE) {
156004ac863bSchristos 		    lex_error("cos result out of range");
156104ac863bSchristos 		    YYABORT;
156204ac863bSchristos 		  }
156304ac863bSchristos 		}
156404ac863bSchristos 	| ATAN2 '(' any_expr ',' any_expr ')'
156504ac863bSchristos 		{
156604ac863bSchristos 		  errno = 0;
156704ac863bSchristos 		  $$ = atan2($3, $5);
156804ac863bSchristos 		  if (errno == EDOM) {
156904ac863bSchristos 		    lex_error("atan2 argument out of domain");
157004ac863bSchristos 		    YYABORT;
157104ac863bSchristos 		  }
157204ac863bSchristos 		  if (errno == ERANGE) {
157304ac863bSchristos 		    lex_error("atan2 result out of range");
157404ac863bSchristos 		    YYABORT;
157504ac863bSchristos 		  }
157604ac863bSchristos 		}
157704ac863bSchristos 	| LOG '(' any_expr ')'
157804ac863bSchristos 		{
157904ac863bSchristos 		  errno = 0;
158004ac863bSchristos 		  $$ = log10($3);
158104ac863bSchristos 		  if (errno == ERANGE) {
158204ac863bSchristos 		    lex_error("log result out of range");
158304ac863bSchristos 		    YYABORT;
158404ac863bSchristos 		  }
158504ac863bSchristos 		}
158604ac863bSchristos 	| EXP '(' any_expr ')'
158704ac863bSchristos 		{
158804ac863bSchristos 		  errno = 0;
158904ac863bSchristos 		  $$ = pow(10.0, $3);
159004ac863bSchristos 		  if (errno == ERANGE) {
159104ac863bSchristos 		    lex_error("exp result out of range");
159204ac863bSchristos 		    YYABORT;
159304ac863bSchristos 		  }
159404ac863bSchristos 		}
159504ac863bSchristos 	| SQRT '(' any_expr ')'
159604ac863bSchristos 		{
159704ac863bSchristos 		  errno = 0;
159804ac863bSchristos 		  $$ = sqrt($3);
159904ac863bSchristos 		  if (errno == EDOM) {
160004ac863bSchristos 		    lex_error("sqrt argument out of domain");
160104ac863bSchristos 		    YYABORT;
160204ac863bSchristos 		  }
160304ac863bSchristos 		}
160404ac863bSchristos 	| K_MAX '(' any_expr ',' any_expr ')'
160504ac863bSchristos 		{ $$ = $3 > $5 ? $3 : $5; }
160604ac863bSchristos 	| K_MIN '(' any_expr ',' any_expr ')'
160704ac863bSchristos 		{ $$ = $3 < $5 ? $3 : $5; }
160804ac863bSchristos 	| INT '(' any_expr ')'
160904ac863bSchristos 		{ $$ = floor($3); }
161004ac863bSchristos 	| RAND '(' any_expr ')'
161104ac863bSchristos 		{ $$ = 1.0 + floor(((rand()&0x7fff)/double(0x7fff))*$3); }
161204ac863bSchristos 	| RAND '(' ')'
161304ac863bSchristos 		{
161404ac863bSchristos 		  /* return a random number in the range [0,1) */
161504ac863bSchristos 		  /* portable, but not very random */
161604ac863bSchristos 		  $$ = (rand() & 0x7fff) / double(0x8000);
161704ac863bSchristos 		}
161804ac863bSchristos 	| SRAND '(' any_expr ')'
161904ac863bSchristos 		{
162004ac863bSchristos 		  $$ = 0;
162104ac863bSchristos 		  srand((unsigned int)$3);
162204ac863bSchristos 		}
162304ac863bSchristos 	| expr '<' expr
162404ac863bSchristos 		{ $$ = ($1 < $3); }
162504ac863bSchristos 	| expr LESSEQUAL expr
162604ac863bSchristos 		{ $$ = ($1 <= $3); }
162704ac863bSchristos 	| expr '>' expr
162804ac863bSchristos 		{ $$ = ($1 > $3); }
162904ac863bSchristos 	| expr GREATEREQUAL expr
163004ac863bSchristos 		{ $$ = ($1 >= $3); }
163104ac863bSchristos 	| expr EQUALEQUAL expr
163204ac863bSchristos 		{ $$ = ($1 == $3); }
163304ac863bSchristos 	| expr NOTEQUAL expr
163404ac863bSchristos 		{ $$ = ($1 != $3); }
163504ac863bSchristos 	| expr ANDAND expr
163604ac863bSchristos 		{ $$ = ($1 != 0.0 && $3 != 0.0); }
163704ac863bSchristos 	| expr OROR expr
163804ac863bSchristos 		{ $$ = ($1 != 0.0 || $3 != 0.0); }
163904ac863bSchristos 	| '!' expr
164004ac863bSchristos 		{ $$ = ($2 == 0.0); }
164104ac863bSchristos 
164204ac863bSchristos 	;
164304ac863bSchristos 
164404ac863bSchristos %%
164504ac863bSchristos 
164604ac863bSchristos /* bison defines const to be empty unless __STDC__ is defined, which it
164704ac863bSchristos isn't under cfront */
164804ac863bSchristos 
164904ac863bSchristos #ifdef const
165004ac863bSchristos #undef const
165104ac863bSchristos #endif
165204ac863bSchristos 
165304ac863bSchristos static struct {
165404ac863bSchristos   const char *name;
165504ac863bSchristos   double val;
165604ac863bSchristos   int scaled;		     // non-zero if val should be multiplied by scale
165704ac863bSchristos } defaults_table[] = {
165804ac863bSchristos   { "arcrad", .25, 1 },
165904ac863bSchristos   { "arrowht", .1, 1 },
166004ac863bSchristos   { "arrowwid", .05, 1 },
166104ac863bSchristos   { "circlerad", .25, 1 },
166204ac863bSchristos   { "boxht", .5, 1 },
166304ac863bSchristos   { "boxwid", .75, 1 },
166404ac863bSchristos   { "boxrad", 0.0, 1 },
166504ac863bSchristos   { "dashwid", .05, 1 },
166604ac863bSchristos   { "ellipseht", .5, 1 },
166704ac863bSchristos   { "ellipsewid", .75, 1 },
166804ac863bSchristos   { "moveht", .5, 1 },
166904ac863bSchristos   { "movewid", .5, 1 },
167004ac863bSchristos   { "lineht", .5, 1 },
167104ac863bSchristos   { "linewid", .5, 1 },
167204ac863bSchristos   { "textht", 0.0, 1 },
167304ac863bSchristos   { "textwid", 0.0, 1 },
167404ac863bSchristos   { "scale", 1.0, 0 },
167504ac863bSchristos   { "linethick", -1.0, 0 },		// in points
167604ac863bSchristos   { "fillval", .5, 0 },
167704ac863bSchristos   { "arrowhead", 1.0, 0 },
167804ac863bSchristos   { "maxpswid", 8.5, 0 },
167904ac863bSchristos   { "maxpsht", 11.0, 0 },
168004ac863bSchristos };
168104ac863bSchristos 
lookup_label(const char * label)168204ac863bSchristos place *lookup_label(const char *label)
168304ac863bSchristos {
168404ac863bSchristos   saved_state *state = current_saved_state;
168504ac863bSchristos   PTABLE(place) *tbl = current_table;
168604ac863bSchristos   for (;;) {
168704ac863bSchristos     place *pl = tbl->lookup(label);
168804ac863bSchristos     if (pl)
168904ac863bSchristos       return pl;
169004ac863bSchristos     if (!state)
169104ac863bSchristos       return 0;
169204ac863bSchristos     tbl = state->tbl;
169304ac863bSchristos     state = state->prev;
169404ac863bSchristos   }
169504ac863bSchristos }
169604ac863bSchristos 
define_label(const char * label,const place * pl)169704ac863bSchristos void define_label(const char *label, const place *pl)
169804ac863bSchristos {
169904ac863bSchristos   place *p = new place[1];
170004ac863bSchristos   *p = *pl;
170104ac863bSchristos   current_table->define(label, p);
170204ac863bSchristos }
170304ac863bSchristos 
lookup_variable(const char * name,double * val)170404ac863bSchristos int lookup_variable(const char *name, double *val)
170504ac863bSchristos {
170604ac863bSchristos   place *pl = lookup_label(name);
170704ac863bSchristos   if (pl) {
170804ac863bSchristos     *val = pl->x;
170904ac863bSchristos     return 1;
171004ac863bSchristos   }
171104ac863bSchristos   return 0;
171204ac863bSchristos }
171304ac863bSchristos 
define_variable(const char * name,double val)171404ac863bSchristos void define_variable(const char *name, double val)
171504ac863bSchristos {
171604ac863bSchristos   place *p = new place[1];
171704ac863bSchristos   p->obj = 0;
171804ac863bSchristos   p->x = val;
171904ac863bSchristos   p->y = 0.0;
172004ac863bSchristos   current_table->define(name, p);
172104ac863bSchristos   if (strcmp(name, "scale") == 0) {
172204ac863bSchristos     // When the scale changes, reset all scaled pre-defined variables to
172304ac863bSchristos     // their default values.
172404ac863bSchristos     for (unsigned int i = 0;
172504ac863bSchristos 	 i < sizeof(defaults_table)/sizeof(defaults_table[0]); i++)
172604ac863bSchristos       if (defaults_table[i].scaled)
172704ac863bSchristos 	define_variable(defaults_table[i].name, val*defaults_table[i].val);
172804ac863bSchristos   }
172904ac863bSchristos }
173004ac863bSchristos 
173104ac863bSchristos // called once only (not once per parse)
173204ac863bSchristos 
parse_init()173304ac863bSchristos void parse_init()
173404ac863bSchristos {
173504ac863bSchristos   current_direction = RIGHT_DIRECTION;
173604ac863bSchristos   current_position.x = 0.0;
173704ac863bSchristos   current_position.y = 0.0;
173804ac863bSchristos   // This resets everything to its default value.
173904ac863bSchristos   reset_all();
174004ac863bSchristos }
174104ac863bSchristos 
reset(const char * nm)174204ac863bSchristos void reset(const char *nm)
174304ac863bSchristos {
174404ac863bSchristos   for (unsigned int i = 0;
174504ac863bSchristos        i < sizeof(defaults_table)/sizeof(defaults_table[0]); i++)
174604ac863bSchristos     if (strcmp(nm, defaults_table[i].name) == 0) {
174704ac863bSchristos       double val = defaults_table[i].val;
174804ac863bSchristos       if (defaults_table[i].scaled) {
174904ac863bSchristos 	double scale;
175004ac863bSchristos 	lookup_variable("scale", &scale);
175104ac863bSchristos 	val *= scale;
175204ac863bSchristos       }
175304ac863bSchristos       define_variable(defaults_table[i].name, val);
175404ac863bSchristos       return;
175504ac863bSchristos     }
175604ac863bSchristos   lex_error("`%1' is not a predefined variable", nm);
175704ac863bSchristos }
175804ac863bSchristos 
reset_all()175904ac863bSchristos void reset_all()
176004ac863bSchristos {
176104ac863bSchristos   // We only have to explicitly reset the pre-defined variables that
176204ac863bSchristos   // aren't scaled because `scale' is not scaled, and changing the
176304ac863bSchristos   // value of `scale' will reset all the pre-defined variables that
176404ac863bSchristos   // are scaled.
176504ac863bSchristos   for (unsigned int i = 0;
176604ac863bSchristos        i < sizeof(defaults_table)/sizeof(defaults_table[0]); i++)
176704ac863bSchristos     if (!defaults_table[i].scaled)
176804ac863bSchristos       define_variable(defaults_table[i].name, defaults_table[i].val);
176904ac863bSchristos }
177004ac863bSchristos 
177104ac863bSchristos // called after each parse
177204ac863bSchristos 
parse_cleanup()177304ac863bSchristos void parse_cleanup()
177404ac863bSchristos {
177504ac863bSchristos   while (current_saved_state != 0) {
177604ac863bSchristos     delete current_table;
177704ac863bSchristos     current_table = current_saved_state->tbl;
177804ac863bSchristos     saved_state *tem = current_saved_state;
177904ac863bSchristos     current_saved_state = current_saved_state->prev;
178004ac863bSchristos     delete tem;
178104ac863bSchristos   }
178204ac863bSchristos   assert(current_table == &top_table);
178304ac863bSchristos   PTABLE_ITERATOR(place) iter(current_table);
178404ac863bSchristos   const char *key;
178504ac863bSchristos   place *pl;
178604ac863bSchristos   while (iter.next(&key, &pl))
178704ac863bSchristos     if (pl->obj != 0) {
178804ac863bSchristos       position pos = pl->obj->origin();
178904ac863bSchristos       pl->obj = 0;
179004ac863bSchristos       pl->x = pos.x;
179104ac863bSchristos       pl->y = pos.y;
179204ac863bSchristos     }
179304ac863bSchristos   while (olist.head != 0) {
179404ac863bSchristos     object *tem = olist.head;
179504ac863bSchristos     olist.head = olist.head->next;
179604ac863bSchristos     delete tem;
179704ac863bSchristos   }
179804ac863bSchristos   olist.tail = 0;
179904ac863bSchristos   current_direction = RIGHT_DIRECTION;
180004ac863bSchristos   current_position.x = 0.0;
180104ac863bSchristos   current_position.y = 0.0;
180204ac863bSchristos }
180304ac863bSchristos 
ordinal_postfix(int n)180404ac863bSchristos const char *ordinal_postfix(int n)
180504ac863bSchristos {
180604ac863bSchristos   if (n < 10 || n > 20)
180704ac863bSchristos     switch (n % 10) {
180804ac863bSchristos     case 1:
180904ac863bSchristos       return "st";
181004ac863bSchristos     case 2:
181104ac863bSchristos       return "nd";
181204ac863bSchristos     case 3:
181304ac863bSchristos       return "rd";
181404ac863bSchristos     }
181504ac863bSchristos   return "th";
181604ac863bSchristos }
181704ac863bSchristos 
object_type_name(object_type type)181804ac863bSchristos const char *object_type_name(object_type type)
181904ac863bSchristos {
182004ac863bSchristos   switch (type) {
182104ac863bSchristos   case BOX_OBJECT:
182204ac863bSchristos     return "box";
182304ac863bSchristos   case CIRCLE_OBJECT:
182404ac863bSchristos     return "circle";
182504ac863bSchristos   case ELLIPSE_OBJECT:
182604ac863bSchristos     return "ellipse";
182704ac863bSchristos   case ARC_OBJECT:
182804ac863bSchristos     return "arc";
182904ac863bSchristos   case SPLINE_OBJECT:
183004ac863bSchristos     return "spline";
183104ac863bSchristos   case LINE_OBJECT:
183204ac863bSchristos     return "line";
183304ac863bSchristos   case ARROW_OBJECT:
183404ac863bSchristos     return "arrow";
183504ac863bSchristos   case MOVE_OBJECT:
183604ac863bSchristos     return "move";
183704ac863bSchristos   case TEXT_OBJECT:
183804ac863bSchristos     return "\"\"";
183904ac863bSchristos   case BLOCK_OBJECT:
184004ac863bSchristos     return "[]";
184104ac863bSchristos   case OTHER_OBJECT:
184204ac863bSchristos   case MARK_OBJECT:
184304ac863bSchristos   default:
184404ac863bSchristos     break;
184504ac863bSchristos   }
184604ac863bSchristos   return "object";
184704ac863bSchristos }
184804ac863bSchristos 
184904ac863bSchristos static char sprintf_buf[1024];
185004ac863bSchristos 
format_number(const char * form,double n)185104ac863bSchristos char *format_number(const char *form, double n)
185204ac863bSchristos {
185304ac863bSchristos   if (form == 0)
185404ac863bSchristos     form = "%g";
185504ac863bSchristos   return do_sprintf(form, &n, 1);
185604ac863bSchristos }
185704ac863bSchristos 
do_sprintf(const char * form,const double * v,int nv)185804ac863bSchristos char *do_sprintf(const char *form, const double *v, int nv)
185904ac863bSchristos {
186004ac863bSchristos   string result;
186104ac863bSchristos   int i = 0;
186204ac863bSchristos   string one_format;
186304ac863bSchristos   while (*form) {
186404ac863bSchristos     if (*form == '%') {
186504ac863bSchristos       one_format += *form++;
186604ac863bSchristos       for (; *form != '\0' && strchr("#-+ 0123456789.", *form) != 0; form++)
186704ac863bSchristos 	one_format += *form;
186804ac863bSchristos       if (*form == '\0' || strchr("eEfgG%", *form) == 0) {
186904ac863bSchristos 	lex_error("bad sprintf format");
187004ac863bSchristos 	result += one_format;
187104ac863bSchristos 	result += form;
187204ac863bSchristos 	break;
187304ac863bSchristos       }
187404ac863bSchristos       if (*form == '%') {
187504ac863bSchristos 	one_format += *form++;
187604ac863bSchristos 	one_format += '\0';
187704ac863bSchristos 	snprintf(sprintf_buf, sizeof(sprintf_buf),
187804ac863bSchristos 		 "%s", one_format.contents());
187904ac863bSchristos       }
188004ac863bSchristos       else {
188104ac863bSchristos 	if (i >= nv) {
188204ac863bSchristos 	  lex_error("too few arguments to snprintf");
188304ac863bSchristos 	  result += one_format;
188404ac863bSchristos 	  result += form;
188504ac863bSchristos 	  break;
188604ac863bSchristos 	}
188704ac863bSchristos 	one_format += *form++;
188804ac863bSchristos 	one_format += '\0';
188904ac863bSchristos 	snprintf(sprintf_buf, sizeof(sprintf_buf),
189004ac863bSchristos 		 one_format.contents(), v[i++]);
189104ac863bSchristos       }
189204ac863bSchristos       one_format.clear();
189304ac863bSchristos       result += sprintf_buf;
189404ac863bSchristos     }
189504ac863bSchristos     else
189604ac863bSchristos       result += *form++;
189704ac863bSchristos   }
189804ac863bSchristos   result += '\0';
189904ac863bSchristos   return strsave(result.contents());
190004ac863bSchristos }
1901