1 /* $NetBSD: pic.y,v 1.1.1.4 2006/02/06 18:14:22 wiz Exp $ */
3 /* Copyright (C) 1989, 1990, 1991, 1992, 2000, 2001, 2002, 2003, 2004, 2005
4 Free Software Foundation, Inc.
5 Written by James Clark (jjc@jclark.com)
7 This file is part of groff.
9 groff is free software; you can redistribute it and/or modify it under
10 the terms of the GNU General Public License as published by the Free
11 Software Foundation; either version 2, or (at your option) any later
14 groff is distributed in the hope that it will be useful, but WITHOUT ANY
15 WARRANTY; without even the implied warranty of MERCHANTABILITY or
16 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
19 You should have received a copy of the GNU General Public License along
20 with groff; see the file COPYING. If not, write to the Free Software
21 Foundation, 51 Franklin St - Fifth Floor, Boston, MA 02110-1301, USA. */
27 extern
int delim_flag
;
28 extern
void copy_rest_thru
(const char *, const char *);
29 extern
void copy_file_thru
(const char *, const char *, const char *);
30 extern
void push_body
(const char *);
31 extern
void do_for
(char *var
, double from
, double to
,
32 int by_is_multiplicative
, double by
, char *body
);
33 extern
void do_lookahead
();
35 /* Maximum number of characters produced by printf("%g") */
39 void yyerror(const char *);
41 void reset
(const char *nm
);
44 place
*lookup_label
(const char *);
45 void define_label
(const char *label
, const place
*pl
);
47 direction current_direction
;
48 position current_position
;
50 implement_ptable
(place
)
52 PTABLE
(place
) top_table
;
54 PTABLE
(place
) *current_table
= &top_table
;
55 saved_state
*current_saved_state
= 0;
59 const char *ordinal_postfix
(int n
);
60 const char *object_type_name
(object_type type
);
61 char *format_number
(const char *form
, double n
);
62 char *do_sprintf
(const char *form
, const double *v
, int nv
);
71 struct { double x
, y
; } pair
;
72 struct { double x
; char *body
; } if_data
;
73 struct { char *str
; const char *filename
; int lineno
; } lstr
;
74 struct { double *v
; int nv
; int maxv
; } dv
;
75 struct { double val
; int is_multiplicative
; } by
;
90 %token
<lstr
> COMMAND_LINE
91 %token
<str
> DELIMITED
94 %token LEFT_ARROW_HEAD
95 %token RIGHT_ARROW_HEAD
96 %token DOUBLE_ARROW_HEAD
214 /* this ensures that plot 17 "%g" parses as (plot 17 "%g") */
218 /* give text adjustments higher precedence than TEXT, so that
219 box "foo" above ljust == box ("foo" above ljust)
222 %left LJUST RJUST ABOVE BELOW
225 /* Give attributes that take an optional expression a higher
226 precedence than left and right, so that eg `line chop left'
228 %left CHOP SOLID DASHED DOTTED UP DOWN FILL COLORED OUTLINED
231 %left VARIABLE NUMBER
'(' SIN COS ATAN2 LOG EXP SQRT K_MAX K_MIN INT RAND SRAND LAST
232 %left ORDINAL HERE
'`'
234 %left BOX CIRCLE ELLIPSE ARC LINE ARROW SPLINE
'['
236 /* these need to be lower than '-' */
237 %left HEIGHT RADIUS WIDTH DIAMETER FROM TO AT THICKNESS
239 /* these must have higher precedence than CHOP so that `label %prec CHOP'
241 %left DOT_N DOT_E DOT_W DOT_S DOT_NE DOT_SE DOT_NW DOT_SW DOT_C
242 %left DOT_START DOT_END TOP BOTTOM LEFT_CORNER RIGHT_CORNER
243 %left UPPER LOWER NORTH SOUTH EAST WEST CENTER START END
248 %left EQUALEQUAL NOTEQUAL
249 %left
'<' '>' LESSEQUAL GREATEREQUAL
259 %type
<x
> expr any_expr text_expr
260 %type
<by
> optional_by
261 %type
<pair
> expr_pair position_not_place
262 %type
<if_data
> simple_if
263 %type
<obj
> nth_primitive
265 %type
<pth
> path label_path relative_path
266 %type
<pl
> place label element element_list middle_element_list
267 %type
<spec
> object_spec
268 %type
<pair
> position
269 %type
<obtype
> object_type
270 %type
<n
> optional_ordinal_last ordinal
271 %type
<str
> macro_name until
272 %type
<dv
> sprintf_args
273 %type
<lstr
> text print_args print_arg
282 print_picture
(olist.head
);
288 optional_separator middle_element_list optional_separator
295 | middle_element_list separator element
310 FIGNAME
'=' macro_name
313 graphname
= new
char[strlen
($3) + 1];
314 strcpy
(graphname
, $3);
318 VARIABLE
'=' any_expr
320 define_variable
($1, $3);
323 | VARIABLE
':' '=' any_expr
325 place
*p
= lookup_label
($1);
327 lex_error
("variable `%1' not defined", $1);
336 { current_direction
= UP_DIRECTION
; }
338 { current_direction
= DOWN_DIRECTION
; }
340 { current_direction
= LEFT_DIRECTION
; }
342 { current_direction
= RIGHT_DIRECTION
; }
345 olist.append
(make_command_object
($1.str
, $1.filename
,
350 olist.append
(make_command_object
($2.str
, $2.filename
,
355 fprintf
(stderr
, "%s\n", $2.str
);
365 lex_error
("unsafe to run command `%1'", $3);
375 // do not delete the filename
385 copy_file_thru
($2.str
, $5, $7);
386 // do not delete the filename
398 copy_rest_thru
($4, $6);
402 | FOR VARIABLE
'=' expr TO expr optional_by DO
409 do_for
($2, $4, $6, $7.is_multiplicative
, $7.val
, $10);
435 { define_variable
("scale", 1.0); }
449 | reset_variables VARIABLE
454 | reset_variables
',' VARIABLE
464 | print_args print_arg
466 $$.str
= new
char[strlen
($1.str
) + strlen
($2.str
) + 1];
467 strcpy
($$.str
, $1.str
);
468 strcat
($$.str
, $2.str
);
472 $$.filename
= $1.filename
;
473 $$.lineno
= $1.lineno
;
475 else if
($2.filename
) {
476 $$.filename
= $2.filename
;
477 $$.lineno
= $2.lineno
;
485 $$.str
= new
char[GDIGITS
+ 1];
486 sprintf
($$.str
, "%g", $1);
494 $$.str
= new
char[GDIGITS
+ 2 + GDIGITS
+ 1];
495 sprintf
($$.str
, "%g, %g", $1.x
, $1.y
);
529 $$
= strcmp
($1.str
, $3.str
) == 0;
535 $$
= strcmp
($1.str
, $3.str
) != 0;
539 | text_expr ANDAND text_expr
540 { $$
= ($1 != 0.0 && $3 != 0.0); }
541 | text_expr ANDAND expr
542 { $$
= ($1 != 0.0 && $3 != 0.0); }
543 | expr ANDAND text_expr
544 { $$
= ($1 != 0.0 && $3 != 0.0); }
545 | text_expr OROR text_expr
546 { $$
= ($1 != 0.0 ||
$3 != 0.0); }
547 | text_expr OROR expr
548 { $$
= ($1 != 0.0 ||
$3 != 0.0); }
549 | expr OROR text_expr
550 { $$
= ($1 != 0.0 ||
$3 != 0.0); }
552 { $$
= ($2 == 0.0); }
560 $$.is_multiplicative
= 0;
565 $$.is_multiplicative
= 0;
570 $$.is_multiplicative
= 1;
577 $$.obj
= $1->make_object
(¤t_position
,
583 olist.append
($$.obj
);
585 $$.x
= current_position.x
;
586 $$.y
= current_position.y
;
589 | LABEL
':' optional_separator element
592 define_label
($1, & $$
);
595 | LABEL
':' optional_separator position_not_place
600 define_label
($1, & $$
);
603 | LABEL
':' optional_separator place
606 define_label
($1, & $$
);
611 $
<state
>$.x
= current_position.x
;
612 $
<state
>$.y
= current_position.y
;
613 $
<state
>$.dir
= current_direction
;
617 current_position.x
= $
<state
>2.x
;
618 current_position.y
= $
<state
>2.y
;
619 current_direction
= $
<state
>2.dir
;
628 $$.x
= current_position.x
;
629 $$.y
= current_position.y
;
642 { $$
= new object_spec
(BOX_OBJECT
); }
644 { $$
= new object_spec
(CIRCLE_OBJECT
); }
646 { $$
= new object_spec
(ELLIPSE_OBJECT
); }
649 $$
= new object_spec
(ARC_OBJECT
);
650 $$
->dir
= current_direction
;
654 $$
= new object_spec
(LINE_OBJECT
);
655 lookup_variable
("lineht", & $$
->segment_height
);
656 lookup_variable
("linewid", & $$
->segment_width
);
657 $$
->dir
= current_direction
;
661 $$
= new object_spec
(ARROW_OBJECT
);
662 lookup_variable
("lineht", & $$
->segment_height
);
663 lookup_variable
("linewid", & $$
->segment_width
);
664 $$
->dir
= current_direction
;
668 $$
= new object_spec
(MOVE_OBJECT
);
669 lookup_variable
("moveht", & $$
->segment_height
);
670 lookup_variable
("movewid", & $$
->segment_width
);
671 $$
->dir
= current_direction
;
675 $$
= new object_spec
(SPLINE_OBJECT
);
676 lookup_variable
("lineht", & $$
->segment_height
);
677 lookup_variable
("linewid", & $$
->segment_width
);
678 $$
->dir
= current_direction
;
682 $$
= new object_spec
(TEXT_OBJECT
);
683 $$
->text
= new text_item
($1.str
, $1.filename
, $1.lineno
);
687 $$
= new object_spec
(TEXT_OBJECT
);
688 $$
->text
= new text_item
(format_number
(0, $2), 0, -1);
692 $$
= new object_spec
(TEXT_OBJECT
);
693 $$
->text
= new text_item
(format_number
($3.str
, $2),
694 $3.filename
, $3.lineno
);
699 saved_state
*p
= new saved_state
;
701 p
->x
= current_position.x
;
702 p
->y
= current_position.y
;
703 p
->dir
= current_direction
;
704 p
->tbl
= current_table
;
705 p
->prev
= current_saved_state
;
706 current_position.x
= 0.0;
707 current_position.y
= 0.0;
708 current_table
= new PTABLE
(place
);
709 current_saved_state
= p
;
710 olist.append
(make_mark_object
());
714 current_position.x
= $
<pstate
>2->x
;
715 current_position.y
= $
<pstate
>2->y
;
716 current_direction
= $
<pstate
>2->dir
;
717 $$
= new object_spec
(BLOCK_OBJECT
);
718 olist.wrap_up_block
(& $$
->oblist
);
719 $$
->tbl
= current_table
;
720 current_table
= $
<pstate
>2->tbl
;
721 current_saved_state
= $
<pstate
>2->prev
;
724 | object_spec HEIGHT expr
728 $$
->flags |
= HAS_HEIGHT
;
730 | object_spec RADIUS expr
734 $$
->flags |
= HAS_RADIUS
;
736 | object_spec WIDTH expr
740 $$
->flags |
= HAS_WIDTH
;
742 | object_spec DIAMETER expr
746 $$
->flags |
= HAS_RADIUS
;
748 | object_spec expr %prec HEIGHT
751 $$
->flags |
= HAS_SEGMENT
;
754 $$
->segment_pos.y
+= $2;
757 $$
->segment_pos.y
-= $2;
759 case RIGHT_DIRECTION
:
760 $$
->segment_pos.x
+= $2;
763 $$
->segment_pos.x
-= $2;
770 $$
->dir
= UP_DIRECTION
;
771 $$
->flags |
= HAS_SEGMENT
;
772 $$
->segment_pos.y
+= $$
->segment_height
;
774 | object_spec UP expr
777 $$
->dir
= UP_DIRECTION
;
778 $$
->flags |
= HAS_SEGMENT
;
779 $$
->segment_pos.y
+= $3;
784 $$
->dir
= DOWN_DIRECTION
;
785 $$
->flags |
= HAS_SEGMENT
;
786 $$
->segment_pos.y
-= $$
->segment_height
;
788 | object_spec DOWN expr
791 $$
->dir
= DOWN_DIRECTION
;
792 $$
->flags |
= HAS_SEGMENT
;
793 $$
->segment_pos.y
-= $3;
798 $$
->dir
= RIGHT_DIRECTION
;
799 $$
->flags |
= HAS_SEGMENT
;
800 $$
->segment_pos.x
+= $$
->segment_width
;
802 | object_spec RIGHT expr
805 $$
->dir
= RIGHT_DIRECTION
;
806 $$
->flags |
= HAS_SEGMENT
;
807 $$
->segment_pos.x
+= $3;
812 $$
->dir
= LEFT_DIRECTION
;
813 $$
->flags |
= HAS_SEGMENT
;
814 $$
->segment_pos.x
-= $$
->segment_width
;
816 | object_spec LEFT expr
819 $$
->dir
= LEFT_DIRECTION
;
820 $$
->flags |
= HAS_SEGMENT
;
821 $$
->segment_pos.x
-= $3;
823 | object_spec FROM position
826 $$
->flags |
= HAS_FROM
;
830 | object_spec TO position
833 if
($$
->flags
& HAS_SEGMENT
)
834 $$
->segment_list
= new segment
($$
->segment_pos
,
835 $$
->segment_is_absolute
,
837 $$
->flags |
= HAS_SEGMENT
;
838 $$
->segment_pos.x
= $3.x
;
839 $$
->segment_pos.y
= $3.y
;
840 $$
->segment_is_absolute
= 1;
845 | object_spec AT position
851 if
($$
->type
!= ARC_OBJECT
) {
852 $$
->flags |
= HAS_FROM
;
857 | object_spec WITH path
860 $$
->flags |
= HAS_WITH
;
863 | object_spec WITH position %prec
','
866 $$
->flags |
= HAS_WITH
;
870 $$
->with
= new path
(pos
);
872 | object_spec BY expr_pair
875 $$
->flags |
= HAS_SEGMENT
;
876 $$
->segment_pos.x
+= $3.x
;
877 $$
->segment_pos.y
+= $3.y
;
882 if
($$
->flags
& HAS_SEGMENT
) {
883 $$
->segment_list
= new segment
($$
->segment_pos
,
884 $$
->segment_is_absolute
,
886 $$
->flags
&= ~HAS_SEGMENT
;
887 $$
->segment_pos.x
= $$
->segment_pos.y
= 0.0;
888 $$
->segment_is_absolute
= 0;
898 $$
->flags |
= IS_DOTTED
;
899 lookup_variable
("dashwid", & $$
->dash_width
);
901 | object_spec DOTTED expr
904 $$
->flags |
= IS_DOTTED
;
910 $$
->flags |
= IS_DASHED
;
911 lookup_variable
("dashwid", & $$
->dash_width
);
913 | object_spec DASHED expr
916 $$
->flags |
= IS_DASHED
;
922 $$
->flags |
= IS_DEFAULT_FILLED
;
924 | object_spec FILL expr
927 $$
->flags |
= IS_FILLED
;
930 | object_spec SHADED text
933 $$
->flags |
= (IS_SHADED | IS_FILLED
);
934 $$
->shaded
= new
char[strlen
($3.str
)+1];
935 strcpy
($$
->shaded
, $3.str
);
937 | object_spec COLORED text
940 $$
->flags |
= (IS_SHADED | IS_OUTLINED | IS_FILLED
);
941 $$
->shaded
= new
char[strlen
($3.str
)+1];
942 strcpy
($$
->shaded
, $3.str
);
943 $$
->outlined
= new
char[strlen
($3.str
)+1];
944 strcpy
($$
->outlined
, $3.str
);
946 | object_spec OUTLINED text
949 $$
->flags |
= IS_OUTLINED
;
950 $$
->outlined
= new
char[strlen
($3.str
)+1];
951 strcpy
($$
->outlined
, $3.str
);
956 // line chop chop means line chop 0 chop 0
957 if
($$
->flags
& IS_DEFAULT_CHOPPED
) {
958 $$
->flags |
= IS_CHOPPED
;
959 $$
->flags
&= ~IS_DEFAULT_CHOPPED
;
960 $$
->start_chop
= $$
->end_chop
= 0.0;
962 else if
($$
->flags
& IS_CHOPPED
) {
966 $$
->flags |
= IS_DEFAULT_CHOPPED
;
969 | object_spec CHOP expr
972 if
($$
->flags
& IS_DEFAULT_CHOPPED
) {
973 $$
->flags |
= IS_CHOPPED
;
974 $$
->flags
&= ~IS_DEFAULT_CHOPPED
;
975 $$
->start_chop
= 0.0;
978 else if
($$
->flags
& IS_CHOPPED
) {
982 $$
->start_chop
= $$
->end_chop
= $3;
983 $$
->flags |
= IS_CHOPPED
;
989 $$
->flags |
= IS_SAME
;
991 | object_spec INVISIBLE
994 $$
->flags |
= IS_INVISIBLE
;
996 | object_spec LEFT_ARROW_HEAD
999 $$
->flags |
= HAS_LEFT_ARROW_HEAD
;
1001 | object_spec RIGHT_ARROW_HEAD
1004 $$
->flags |
= HAS_RIGHT_ARROW_HEAD
;
1006 | object_spec DOUBLE_ARROW_HEAD
1009 $$
->flags |
= (HAS_LEFT_ARROW_HEAD|HAS_RIGHT_ARROW_HEAD
);
1014 $$
->flags |
= IS_CLOCKWISE
;
1019 $$
->flags
&= ~IS_CLOCKWISE
;
1021 | object_spec text %prec TEXT
1025 for
(p
= & $$
->text
; *p
; p
= &(*p
)->next
)
1027 *p
= new text_item
($2.str
, $2.filename
, $2.lineno
);
1034 for
(p
= $$
->text
; p
->next
; p
= p
->next
)
1036 p
->adj.h
= LEFT_ADJUST
;
1044 for
(p
= $$
->text
; p
->next
; p
= p
->next
)
1046 p
->adj.h
= RIGHT_ADJUST
;
1054 for
(p
= $$
->text
; p
->next
; p
= p
->next
)
1056 p
->adj.v
= ABOVE_ADJUST
;
1064 for
(p
= $$
->text
; p
->next
; p
= p
->next
)
1066 p
->adj.v
= BELOW_ADJUST
;
1069 | object_spec THICKNESS expr
1072 $$
->flags |
= HAS_THICKNESS
;
1075 | object_spec ALIGNED
1078 $$
->flags |
= IS_ALIGNED
;
1085 | SPRINTF
'(' TEXT sprintf_args
')'
1087 $$.filename
= $3.filename
;
1088 $$.lineno
= $3.lineno
;
1089 $$.str
= do_sprintf
($3.str
, $4.v
, $4.nv
);
1102 | sprintf_args
',' expr
1105 if
($$.nv
>= $$.maxv
) {
1107 $$.v
= new
double[4];
1111 double *oldv
= $$.v
;
1114 $$.v
= new
double[$$.maxv
];
1115 memcpy
($$.v
, oldv
, $$.nv
*sizeof
(double));
1117 // workaround for bug in Compaq C++ V6.5-033
1118 // for Compaq Tru64 UNIX V5.1A (Rev. 1885)
1119 double *foo
= new
double[$$.maxv
];
1120 memcpy
(foo
, oldv
, $$.nv
*sizeof
(double));
1151 | position
'+' expr_pair
1156 |
'(' position
'+' expr_pair
')'
1161 | position
'-' expr_pair
1166 |
'(' position
'-' expr_pair
')'
1171 |
'(' position
',' position
')'
1176 | expr between position AND position
1178 $$.x
= (1.0 - $1)*$3.x
+ $1*$5.x
;
1179 $$.y
= (1.0 - $1)*$3.y
+ $1*$5.y
;
1181 |
'(' expr between position AND position
')'
1183 $$.x
= (1.0 - $2)*$4.x
+ $2*$6.x
;
1184 $$.y
= (1.0 - $2)*$4.y
+ $2*$6.y
;
1186 | expr
'<' position
',' position
'>'
1188 $$.x
= (1.0 - $1)*$3.x
+ $1*$5.x
;
1189 $$.y
= (1.0 - $1)*$3.y
+ $1*$5.y
;
1191 |
'(' expr
'<' position
',' position
'>' ')'
1193 $$.x
= (1.0 - $2)*$4.x
+ $2*$6.x
;
1194 $$.y
= (1.0 - $2)*$4.y
+ $2*$6.y
;
1200 | OF THE WAY BETWEEN
1214 /* line at A left == line (at A) left */
1220 if
(!pth.follow
($1, & $$
))
1226 if
(!pth.follow
($2, & $$
))
1232 if
(!pth.follow
($3, & $$
))
1237 $$.x
= current_position.x
;
1238 $$.y
= current_position.y
;
1246 place
*p
= lookup_label
($1);
1248 lex_error
("there is no place `%1'", $1);
1259 if
(!pth.follow
($1, & $$
))
1269 // XXX Check for overflow (and non-integers?).
1274 optional_ordinal_last:
1286 for
(p
= olist.head
; p
!= 0; p
= p
->next
)
1287 if
(p
->type
() == $2 && ++count
== $1) {
1292 lex_error
("there is no %1%2 %3", $1, ordinal_postfix
($1),
1293 object_type_name
($2));
1297 | optional_ordinal_last object_type
1301 for
(p
= olist.tail
; p
!= 0; p
= p
->prev
)
1302 if
(p
->type
() == $2 && ++count
== $1) {
1307 lex_error
("there is no %1%2 last %3", $1,
1308 ordinal_postfix
($1), object_type_name
($2));
1316 { $$
= BOX_OBJECT
; }
1318 { $$
= CIRCLE_OBJECT
; }
1320 { $$
= ELLIPSE_OBJECT
; }
1322 { $$
= ARC_OBJECT
; }
1324 { $$
= LINE_OBJECT
; }
1326 { $$
= ARROW_OBJECT
; }
1328 { $$
= SPLINE_OBJECT
; }
1330 { $$
= BLOCK_OBJECT
; }
1332 { $$
= TEXT_OBJECT
; }
1337 { $$
= new path
($2); }
1338 | label_path
'.' LABEL
1347 { $$
= new path
($1); }
1348 /* give this a lower precedence than LEFT and RIGHT so that
1349 [A: box] with .A left == [A: box] with (.A left) */
1350 | label_path %prec TEXT
1362 |
'(' relative_path
',' relative_path
')'
1367 /* The rest of these rules are a compatibility sop. */
1368 | ORDINAL LAST object_type relative_path
1370 lex_warning
("`%1%2 last %3' in `with' argument ignored",
1371 $1, ordinal_postfix
($1), object_type_name
($3));
1374 | LAST object_type relative_path
1376 lex_warning
("`last %1' in `with' argument ignored",
1377 object_type_name
($2));
1380 | ORDINAL object_type relative_path
1382 lex_warning
("`%1%2 %3' in `with' argument ignored",
1383 $1, ordinal_postfix
($1), object_type_name
($2));
1386 | LABEL relative_path
1388 lex_warning
("initial `%1' in `with' argument ignored", $1);
1396 { $$
= &object
::north
; }
1398 { $$
= &object
::east
; }
1400 { $$
= &object
::west
; }
1402 { $$
= &object
::south
; }
1404 { $$
= &object
::north_east
; }
1406 { $$
= &object
:: south_east
; }
1408 { $$
= &object
::north_west
; }
1410 { $$
= &object
::south_west
; }
1412 { $$
= &object
::center
; }
1414 { $$
= &object
::start
; }
1416 { $$
= &object
::end
; }
1418 { $$
= &object
::north
; }
1420 { $$
= &object
::south
; }
1422 { $$
= &object
::west
; }
1424 { $$
= &object
::east
; }
1426 { $$
= &object
::north_west
; }
1428 { $$
= &object
::south_west
; }
1430 { $$
= &object
::north_east
; }
1432 { $$
= &object
::south_east
; }
1434 { $$
= &object
::west
; }
1436 { $$
= &object
::east
; }
1438 { $$
= &object
::north_west
; }
1440 { $$
= &object
::south_west
; }
1441 | UPPER RIGHT_CORNER
1442 { $$
= &object
::north_east
; }
1443 | LOWER RIGHT_CORNER
1444 { $$
= &object
::south_east
; }
1446 { $$
= &object
::north
; }
1448 { $$
= &object
::south
; }
1450 { $$
= &object
::east
; }
1452 { $$
= &object
::west
; }
1454 { $$
= &object
::center
; }
1456 { $$
= &object
::start
; }
1458 { $$
= &object
::end
; }
1464 if
(!lookup_variable
($1, & $$
)) {
1465 lex_error
("there is no variable `%1'", $1);
1475 $$
= $1.obj
->origin
().x
;
1482 $$
= $1.obj
->origin
().y
;
1489 $$
= $1.obj
->height
();
1496 $$
= $1.obj
->width
();
1503 $$
= $1.obj
->radius
();
1516 lex_error
("division by zero");
1524 lex_error
("modulus by zero");
1533 if
(errno
== EDOM
) {
1534 lex_error
("arguments to `^' operator out of domain");
1537 if
(errno
== ERANGE
) {
1538 lex_error
("result of `^' operator out of range");
1542 |
'-' expr %prec
'!'
1546 | SIN
'(' any_expr
')'
1550 if
(errno
== ERANGE
) {
1551 lex_error
("sin result out of range");
1555 | COS
'(' any_expr
')'
1559 if
(errno
== ERANGE
) {
1560 lex_error
("cos result out of range");
1564 | ATAN2
'(' any_expr
',' any_expr
')'
1568 if
(errno
== EDOM
) {
1569 lex_error
("atan2 argument out of domain");
1572 if
(errno
== ERANGE
) {
1573 lex_error
("atan2 result out of range");
1577 | LOG
'(' any_expr
')'
1581 if
(errno
== ERANGE
) {
1582 lex_error
("log result out of range");
1586 | EXP
'(' any_expr
')'
1590 if
(errno
== ERANGE
) {
1591 lex_error
("exp result out of range");
1595 | SQRT
'(' any_expr
')'
1599 if
(errno
== EDOM
) {
1600 lex_error
("sqrt argument out of domain");
1604 | K_MAX
'(' any_expr
',' any_expr
')'
1605 { $$
= $3 > $5 ?
$3 : $5; }
1606 | K_MIN
'(' any_expr
',' any_expr
')'
1607 { $$
= $3 < $5 ?
$3 : $5; }
1608 | INT
'(' any_expr
')'
1610 | RAND
'(' any_expr
')'
1611 { $$
= 1.0 + floor
(((rand
()&0x7fff)/double(0x7fff))*$3); }
1614 /* return a random number in the range [0,1) */
1615 /* portable, but not very random */
1616 $$
= (rand
() & 0x7fff) / double(0x8000);
1618 | SRAND
'(' any_expr
')'
1621 srand
((unsigned int)$3);
1625 | expr LESSEQUAL expr
1626 { $$
= ($1 <= $3); }
1629 | expr GREATEREQUAL expr
1630 { $$
= ($1 >= $3); }
1631 | expr EQUALEQUAL expr
1632 { $$
= ($1 == $3); }
1633 | expr NOTEQUAL expr
1634 { $$
= ($1 != $3); }
1636 { $$
= ($1 != 0.0 && $3 != 0.0); }
1638 { $$
= ($1 != 0.0 ||
$3 != 0.0); }
1640 { $$
= ($2 == 0.0); }
1646 /* bison defines const to be empty unless __STDC__ is defined, which it
1647 isn't under cfront */
1656 int scaled
; // non-zero if val should be multiplied by scale
1657 } defaults_table
[] = {
1658 { "arcrad", .25, 1 },
1659 { "arrowht", .1, 1 },
1660 { "arrowwid", .05, 1 },
1661 { "circlerad", .25, 1 },
1663 { "boxwid", .75, 1 },
1664 { "boxrad", 0.0, 1 },
1665 { "dashwid", .05, 1 },
1666 { "ellipseht", .5, 1 },
1667 { "ellipsewid", .75, 1 },
1668 { "moveht", .5, 1 },
1669 { "movewid", .5, 1 },
1670 { "lineht", .5, 1 },
1671 { "linewid", .5, 1 },
1672 { "textht", 0.0, 1 },
1673 { "textwid", 0.0, 1 },
1674 { "scale", 1.0, 0 },
1675 { "linethick", -1.0, 0 }, // in points
1676 { "fillval", .5, 0 },
1677 { "arrowhead", 1.0, 0 },
1678 { "maxpswid", 8.5, 0 },
1679 { "maxpsht", 11.0, 0 },
1682 place
*lookup_label
(const char *label
)
1684 saved_state
*state
= current_saved_state
;
1685 PTABLE
(place
) *tbl
= current_table
;
1687 place
*pl
= tbl
->lookup
(label
);
1693 state
= state
->prev
;
1697 void define_label
(const char *label
, const place
*pl
)
1699 place
*p
= new place
[1];
1701 current_table
->define
(label
, p
);
1704 int lookup_variable
(const char *name
, double *val
)
1706 place
*pl
= lookup_label
(name
);
1714 void define_variable
(const char *name
, double val
)
1716 place
*p
= new place
[1];
1720 current_table
->define
(name
, p
);
1721 if
(strcmp
(name
, "scale") == 0) {
1722 // When the scale changes, reset all scaled pre-defined variables to
1723 // their default values.
1724 for
(unsigned int i
= 0;
1725 i
< sizeof
(defaults_table
)/sizeof
(defaults_table
[0]); i
++)
1726 if
(defaults_table
[i
].scaled
)
1727 define_variable
(defaults_table
[i
].name
, val
*defaults_table
[i
].val
);
1731 // called once only (not once per parse)
1735 current_direction
= RIGHT_DIRECTION
;
1736 current_position.x
= 0.0;
1737 current_position.y
= 0.0;
1738 // This resets everything to its default value.
1742 void reset
(const char *nm
)
1744 for
(unsigned int i
= 0;
1745 i
< sizeof
(defaults_table
)/sizeof
(defaults_table
[0]); i
++)
1746 if
(strcmp
(nm
, defaults_table
[i
].name
) == 0) {
1747 double val
= defaults_table
[i
].val
;
1748 if
(defaults_table
[i
].scaled
) {
1750 lookup_variable
("scale", &scale
);
1753 define_variable
(defaults_table
[i
].name
, val
);
1756 lex_error
("`%1' is not a predefined variable", nm
);
1761 // We only have to explicitly reset the pre-defined variables that
1762 // aren't scaled because `scale' is not scaled, and changing the
1763 // value of `scale' will reset all the pre-defined variables that
1765 for
(unsigned int i
= 0;
1766 i
< sizeof
(defaults_table
)/sizeof
(defaults_table
[0]); i
++)
1767 if
(!defaults_table
[i
].scaled
)
1768 define_variable
(defaults_table
[i
].name
, defaults_table
[i
].val
);
1771 // called after each parse
1773 void parse_cleanup
()
1775 while
(current_saved_state
!= 0) {
1776 delete current_table
;
1777 current_table
= current_saved_state
->tbl
;
1778 saved_state
*tem
= current_saved_state
;
1779 current_saved_state
= current_saved_state
->prev
;
1782 assert
(current_table
== &top_table
);
1783 PTABLE_ITERATOR
(place
) iter
(current_table
);
1786 while
(iter.next
(&key
, &pl
))
1788 position pos
= pl
->obj
->origin
();
1793 while
(olist.head
!= 0) {
1794 object
*tem
= olist.head
;
1795 olist.head
= olist.head
->next
;
1799 current_direction
= RIGHT_DIRECTION
;
1800 current_position.x
= 0.0;
1801 current_position.y
= 0.0;
1804 const char *ordinal_postfix
(int n
)
1806 if
(n
< 10 || n
> 20)
1818 const char *object_type_name
(object_type type
)
1825 case ELLIPSE_OBJECT
:
1849 static char sprintf_buf
[1024];
1851 char *format_number
(const char *form
, double n
)
1855 return do_sprintf
(form
, &n
, 1);
1858 char *do_sprintf
(const char *form
, const double *v
, int nv
)
1865 one_format
+= *form
++;
1866 for
(; *form
!= '\0' && strchr
("#-+ 0123456789.", *form
) != 0; form
++)
1867 one_format
+= *form
;
1868 if
(*form
== '\0' || strchr
("eEfgG%", *form
) == 0) {
1869 lex_error
("bad sprintf format");
1870 result
+= one_format
;
1875 one_format
+= *form
++;
1877 snprintf
(sprintf_buf
, sizeof
(sprintf_buf
),
1878 "%s", one_format.contents
());
1882 lex_error
("too few arguments to snprintf");
1883 result
+= one_format
;
1887 one_format
+= *form
++;
1889 snprintf
(sprintf_buf
, sizeof
(sprintf_buf
),
1890 one_format.contents
(), v
[i
++]);
1893 result
+= sprintf_buf
;
1899 return strsave
(result.contents
());