PageRenderTime 63ms CodeModel.GetById 23ms RepoModel.GetById 0ms app.codeStats 0ms

/src/netbsd/src/gnu/dist/groff/src/preproc/pic/pic.y

https://bitbucket.org/killerpenguinassassins/open_distrib_devel
Happy | 1900 lines | 1808 code | 92 blank | 0 comment | 0 complexity | 95464894ea4277f43fbbb0dd4ed49d1d MD5 | raw file
Possible License(s): CC0-1.0, MIT, LGPL-2.0, LGPL-3.0, WTFPL, GPL-2.0, BSD-2-Clause, AGPL-3.0, CC-BY-SA-3.0, MPL-2.0, JSON, BSD-3-Clause-No-Nuclear-License-2014, LGPL-2.1, CPL-1.0, AGPL-1.0, 0BSD, ISC, Apache-2.0, GPL-3.0, IPL-1.0, MPL-2.0-no-copyleft-exception, BSD-3-Clause
  1. /* $NetBSD: pic.y,v 1.5 2006/02/06 18:25:48 wiz Exp $ */
  2. /* Copyright (C) 1989, 1990, 1991, 1992, 2000, 2001, 2002, 2003, 2004, 2005
  3. Free Software Foundation, Inc.
  4. Written by James Clark (jjc@jclark.com)
  5. This file is part of groff.
  6. groff is free software; you can redistribute it and/or modify it under
  7. the terms of the GNU General Public License as published by the Free
  8. Software Foundation; either version 2, or (at your option) any later
  9. version.
  10. groff is distributed in the hope that it will be useful, but WITHOUT ANY
  11. WARRANTY; without even the implied warranty of MERCHANTABILITY or
  12. FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
  13. for more details.
  14. You should have received a copy of the GNU General Public License along
  15. with groff; see the file COPYING. If not, write to the Free Software
  16. Foundation, 51 Franklin St - Fifth Floor, Boston, MA 02110-1301, USA. */
  17. %{
  18. #include "pic.h"
  19. #include "ptable.h"
  20. #include "object.h"
  21. extern int delim_flag;
  22. extern void copy_rest_thru(const char *, const char *);
  23. extern void copy_file_thru(const char *, const char *, const char *);
  24. extern void push_body(const char *);
  25. extern void do_for(char *var, double from, double to,
  26. int by_is_multiplicative, double by, char *body);
  27. extern void do_lookahead();
  28. /* Maximum number of characters produced by printf("%g") */
  29. #define GDIGITS 14
  30. int yylex();
  31. void yyerror(const char *);
  32. void reset(const char *nm);
  33. void reset_all();
  34. place *lookup_label(const char *);
  35. void define_label(const char *label, const place *pl);
  36. direction current_direction;
  37. position current_position;
  38. implement_ptable(place)
  39. PTABLE(place) top_table;
  40. PTABLE(place) *current_table = &top_table;
  41. saved_state *current_saved_state = 0;
  42. object_list olist;
  43. const char *ordinal_postfix(int n);
  44. const char *object_type_name(object_type type);
  45. char *format_number(const char *form, double n);
  46. char *do_sprintf(const char *form, const double *v, int nv);
  47. %}
  48. %union {
  49. char *str;
  50. int n;
  51. double x;
  52. struct { double x, y; } pair;
  53. struct { double x; char *body; } if_data;
  54. struct { char *str; const char *filename; int lineno; } lstr;
  55. struct { double *v; int nv; int maxv; } dv;
  56. struct { double val; int is_multiplicative; } by;
  57. place pl;
  58. object *obj;
  59. corner crn;
  60. path *pth;
  61. object_spec *spec;
  62. saved_state *pstate;
  63. graphics_state state;
  64. object_type obtype;
  65. }
  66. %token <str> LABEL
  67. %token <str> VARIABLE
  68. %token <x> NUMBER
  69. %token <lstr> TEXT
  70. %token <lstr> COMMAND_LINE
  71. %token <str> DELIMITED
  72. %token <n> ORDINAL
  73. %token TH
  74. %token LEFT_ARROW_HEAD
  75. %token RIGHT_ARROW_HEAD
  76. %token DOUBLE_ARROW_HEAD
  77. %token LAST
  78. %token UP
  79. %token DOWN
  80. %token LEFT
  81. %token RIGHT
  82. %token BOX
  83. %token CIRCLE
  84. %token ELLIPSE
  85. %token ARC
  86. %token LINE
  87. %token ARROW
  88. %token MOVE
  89. %token SPLINE
  90. %token HEIGHT
  91. %token RADIUS
  92. %token FIGNAME
  93. %token WIDTH
  94. %token DIAMETER
  95. %token UP
  96. %token DOWN
  97. %token RIGHT
  98. %token LEFT
  99. %token FROM
  100. %token TO
  101. %token AT
  102. %token WITH
  103. %token BY
  104. %token THEN
  105. %token SOLID
  106. %token DOTTED
  107. %token DASHED
  108. %token CHOP
  109. %token SAME
  110. %token INVISIBLE
  111. %token LJUST
  112. %token RJUST
  113. %token ABOVE
  114. %token BELOW
  115. %token OF
  116. %token THE
  117. %token WAY
  118. %token BETWEEN
  119. %token AND
  120. %token HERE
  121. %token DOT_N
  122. %token DOT_E
  123. %token DOT_W
  124. %token DOT_S
  125. %token DOT_NE
  126. %token DOT_SE
  127. %token DOT_NW
  128. %token DOT_SW
  129. %token DOT_C
  130. %token DOT_START
  131. %token DOT_END
  132. %token DOT_X
  133. %token DOT_Y
  134. %token DOT_HT
  135. %token DOT_WID
  136. %token DOT_RAD
  137. %token SIN
  138. %token COS
  139. %token ATAN2
  140. %token LOG
  141. %token EXP
  142. %token SQRT
  143. %token K_MAX
  144. %token K_MIN
  145. %token INT
  146. %token RAND
  147. %token SRAND
  148. %token COPY
  149. %token THRU
  150. %token TOP
  151. %token BOTTOM
  152. %token UPPER
  153. %token LOWER
  154. %token SH
  155. %token PRINT
  156. %token CW
  157. %token CCW
  158. %token FOR
  159. %token DO
  160. %token IF
  161. %token ELSE
  162. %token ANDAND
  163. %token OROR
  164. %token NOTEQUAL
  165. %token EQUALEQUAL
  166. %token LESSEQUAL
  167. %token GREATEREQUAL
  168. %token LEFT_CORNER
  169. %token RIGHT_CORNER
  170. %token NORTH
  171. %token SOUTH
  172. %token EAST
  173. %token WEST
  174. %token CENTER
  175. %token END
  176. %token START
  177. %token RESET
  178. %token UNTIL
  179. %token PLOT
  180. %token THICKNESS
  181. %token FILL
  182. %token COLORED
  183. %token OUTLINED
  184. %token SHADED
  185. %token ALIGNED
  186. %token SPRINTF
  187. %token COMMAND
  188. %token DEFINE
  189. %token UNDEF
  190. %left '.'
  191. /* this ensures that plot 17 "%g" parses as (plot 17 "%g") */
  192. %left PLOT
  193. %left TEXT SPRINTF
  194. /* give text adjustments higher precedence than TEXT, so that
  195. box "foo" above ljust == box ("foo" above ljust)
  196. */
  197. %left LJUST RJUST ABOVE BELOW
  198. %left LEFT RIGHT
  199. /* Give attributes that take an optional expression a higher
  200. precedence than left and right, so that eg `line chop left'
  201. parses properly. */
  202. %left CHOP SOLID DASHED DOTTED UP DOWN FILL COLORED OUTLINED
  203. %left LABEL
  204. %left VARIABLE NUMBER '(' SIN COS ATAN2 LOG EXP SQRT K_MAX K_MIN INT RAND SRAND LAST
  205. %left ORDINAL HERE '`'
  206. %left BOX CIRCLE ELLIPSE ARC LINE ARROW SPLINE '['
  207. /* these need to be lower than '-' */
  208. %left HEIGHT RADIUS WIDTH DIAMETER FROM TO AT THICKNESS
  209. /* these must have higher precedence than CHOP so that `label %prec CHOP'
  210. works */
  211. %left DOT_N DOT_E DOT_W DOT_S DOT_NE DOT_SE DOT_NW DOT_SW DOT_C
  212. %left DOT_START DOT_END TOP BOTTOM LEFT_CORNER RIGHT_CORNER
  213. %left UPPER LOWER NORTH SOUTH EAST WEST CENTER START END
  214. %left ','
  215. %left OROR
  216. %left ANDAND
  217. %left EQUALEQUAL NOTEQUAL
  218. %left '<' '>' LESSEQUAL GREATEREQUAL
  219. %left BETWEEN OF
  220. %left AND
  221. %left '+' '-'
  222. %left '*' '/' '%'
  223. %right '!'
  224. %right '^'
  225. %type <x> expr any_expr text_expr
  226. %type <by> optional_by
  227. %type <pair> expr_pair position_not_place
  228. %type <if_data> simple_if
  229. %type <obj> nth_primitive
  230. %type <crn> corner
  231. %type <pth> path label_path relative_path
  232. %type <pl> place label element element_list middle_element_list
  233. %type <spec> object_spec
  234. %type <pair> position
  235. %type <obtype> object_type
  236. %type <n> optional_ordinal_last ordinal
  237. %type <str> macro_name until
  238. %type <dv> sprintf_args
  239. %type <lstr> text print_args print_arg
  240. %%
  241. top:
  242. optional_separator
  243. | element_list
  244. {
  245. if (olist.head)
  246. print_picture(olist.head);
  247. }
  248. ;
  249. element_list:
  250. optional_separator middle_element_list optional_separator
  251. { $$ = $2; }
  252. ;
  253. middle_element_list:
  254. element
  255. { $$ = $1; }
  256. | middle_element_list separator element
  257. { $$ = $1; }
  258. ;
  259. optional_separator:
  260. /* empty */
  261. | separator
  262. ;
  263. separator:
  264. ';'
  265. | separator ';'
  266. ;
  267. placeless_element:
  268. FIGNAME '=' macro_name
  269. {
  270. a_delete graphname;
  271. graphname = new char[strlen($3) + 1];
  272. strcpy(graphname, $3);
  273. a_delete $3;
  274. }
  275. |
  276. VARIABLE '=' any_expr
  277. {
  278. define_variable($1, $3);
  279. a_delete $1;
  280. }
  281. | VARIABLE ':' '=' any_expr
  282. {
  283. place *p = lookup_label($1);
  284. if (!p) {
  285. lex_error("variable `%1' not defined", $1);
  286. YYABORT;
  287. }
  288. p->obj = 0;
  289. p->x = $4;
  290. p->y = 0.0;
  291. a_delete $1;
  292. }
  293. | UP
  294. { current_direction = UP_DIRECTION; }
  295. | DOWN
  296. { current_direction = DOWN_DIRECTION; }
  297. | LEFT
  298. { current_direction = LEFT_DIRECTION; }
  299. | RIGHT
  300. { current_direction = RIGHT_DIRECTION; }
  301. | COMMAND_LINE
  302. {
  303. olist.append(make_command_object($1.str, $1.filename,
  304. $1.lineno));
  305. }
  306. | COMMAND print_args
  307. {
  308. olist.append(make_command_object($2.str, $2.filename,
  309. $2.lineno));
  310. }
  311. | PRINT print_args
  312. {
  313. fprintf(stderr, "%s\n", $2.str);
  314. a_delete $2.str;
  315. fflush(stderr);
  316. }
  317. | SH
  318. { delim_flag = 1; }
  319. DELIMITED
  320. {
  321. delim_flag = 0;
  322. if (safer_flag)
  323. lex_error("unsafe to run command `%1'", $3);
  324. else
  325. system($3);
  326. a_delete $3;
  327. }
  328. | COPY TEXT
  329. {
  330. if (yychar < 0)
  331. do_lookahead();
  332. do_copy($2.str);
  333. // do not delete the filename
  334. }
  335. | COPY TEXT THRU
  336. { delim_flag = 2; }
  337. DELIMITED
  338. { delim_flag = 0; }
  339. until
  340. {
  341. if (yychar < 0)
  342. do_lookahead();
  343. copy_file_thru($2.str, $5, $7);
  344. // do not delete the filename
  345. a_delete $5;
  346. a_delete $7;
  347. }
  348. | COPY THRU
  349. { delim_flag = 2; }
  350. DELIMITED
  351. { delim_flag = 0; }
  352. until
  353. {
  354. if (yychar < 0)
  355. do_lookahead();
  356. copy_rest_thru($4, $6);
  357. a_delete $4;
  358. a_delete $6;
  359. }
  360. | FOR VARIABLE '=' expr TO expr optional_by DO
  361. { delim_flag = 1; }
  362. DELIMITED
  363. {
  364. delim_flag = 0;
  365. if (yychar < 0)
  366. do_lookahead();
  367. do_for($2, $4, $6, $7.is_multiplicative, $7.val, $10);
  368. }
  369. | simple_if
  370. {
  371. if (yychar < 0)
  372. do_lookahead();
  373. if ($1.x != 0.0)
  374. push_body($1.body);
  375. a_delete $1.body;
  376. }
  377. | simple_if ELSE
  378. { delim_flag = 1; }
  379. DELIMITED
  380. {
  381. delim_flag = 0;
  382. if (yychar < 0)
  383. do_lookahead();
  384. if ($1.x != 0.0)
  385. push_body($1.body);
  386. else
  387. push_body($4);
  388. a_delete $1.body;
  389. a_delete $4;
  390. }
  391. | reset_variables
  392. | RESET
  393. { define_variable("scale", 1.0); }
  394. ;
  395. macro_name:
  396. VARIABLE
  397. | LABEL
  398. ;
  399. reset_variables:
  400. RESET VARIABLE
  401. {
  402. reset($2);
  403. a_delete $2;
  404. }
  405. | reset_variables VARIABLE
  406. {
  407. reset($2);
  408. a_delete $2;
  409. }
  410. | reset_variables ',' VARIABLE
  411. {
  412. reset($3);
  413. a_delete $3;
  414. }
  415. ;
  416. print_args:
  417. print_arg
  418. { $$ = $1; }
  419. | print_args print_arg
  420. {
  421. $$.str = new char[strlen($1.str) + strlen($2.str) + 1];
  422. strcpy($$.str, $1.str);
  423. strcat($$.str, $2.str);
  424. a_delete $1.str;
  425. a_delete $2.str;
  426. if ($1.filename) {
  427. $$.filename = $1.filename;
  428. $$.lineno = $1.lineno;
  429. }
  430. else if ($2.filename) {
  431. $$.filename = $2.filename;
  432. $$.lineno = $2.lineno;
  433. }
  434. }
  435. ;
  436. print_arg:
  437. expr %prec ','
  438. {
  439. $$.str = new char[GDIGITS + 1];
  440. sprintf($$.str, "%g", $1);
  441. $$.filename = 0;
  442. $$.lineno = 0;
  443. }
  444. | text
  445. { $$ = $1; }
  446. | position %prec ','
  447. {
  448. $$.str = new char[GDIGITS + 2 + GDIGITS + 1];
  449. sprintf($$.str, "%g, %g", $1.x, $1.y);
  450. $$.filename = 0;
  451. $$.lineno = 0;
  452. }
  453. ;
  454. simple_if:
  455. IF any_expr THEN
  456. { delim_flag = 1; }
  457. DELIMITED
  458. {
  459. delim_flag = 0;
  460. $$.x = $2;
  461. $$.body = $5;
  462. }
  463. ;
  464. until:
  465. /* empty */
  466. { $$ = 0; }
  467. | UNTIL TEXT
  468. { $$ = $2.str; }
  469. ;
  470. any_expr:
  471. expr
  472. { $$ = $1; }
  473. | text_expr
  474. { $$ = $1; }
  475. ;
  476. text_expr:
  477. text EQUALEQUAL text
  478. {
  479. $$ = strcmp($1.str, $3.str) == 0;
  480. a_delete $1.str;
  481. a_delete $3.str;
  482. }
  483. | text NOTEQUAL text
  484. {
  485. $$ = strcmp($1.str, $3.str) != 0;
  486. a_delete $1.str;
  487. a_delete $3.str;
  488. }
  489. | text_expr ANDAND text_expr
  490. { $$ = ($1 != 0.0 && $3 != 0.0); }
  491. | text_expr ANDAND expr
  492. { $$ = ($1 != 0.0 && $3 != 0.0); }
  493. | expr ANDAND text_expr
  494. { $$ = ($1 != 0.0 && $3 != 0.0); }
  495. | text_expr OROR text_expr
  496. { $$ = ($1 != 0.0 || $3 != 0.0); }
  497. | text_expr OROR expr
  498. { $$ = ($1 != 0.0 || $3 != 0.0); }
  499. | expr OROR text_expr
  500. { $$ = ($1 != 0.0 || $3 != 0.0); }
  501. | '!' text_expr
  502. { $$ = ($2 == 0.0); }
  503. ;
  504. optional_by:
  505. /* empty */
  506. {
  507. $$.val = 1.0;
  508. $$.is_multiplicative = 0;
  509. }
  510. | BY expr
  511. {
  512. $$.val = $2;
  513. $$.is_multiplicative = 0;
  514. }
  515. | BY '*' expr
  516. {
  517. $$.val = $3;
  518. $$.is_multiplicative = 1;
  519. }
  520. ;
  521. element:
  522. object_spec
  523. {
  524. $$.obj = $1->make_object(&current_position,
  525. &current_direction);
  526. if ($$.obj == 0)
  527. YYABORT;
  528. delete $1;
  529. if ($$.obj)
  530. olist.append($$.obj);
  531. else {
  532. $$.x = current_position.x;
  533. $$.y = current_position.y;
  534. }
  535. }
  536. | LABEL ':' optional_separator element
  537. {
  538. $$ = $4;
  539. define_label($1, & $$);
  540. a_delete $1;
  541. }
  542. | LABEL ':' optional_separator position_not_place
  543. {
  544. $$.obj = 0;
  545. $$.x = $4.x;
  546. $$.y = $4.y;
  547. define_label($1, & $$);
  548. a_delete $1;
  549. }
  550. | LABEL ':' optional_separator place
  551. {
  552. $$ = $4;
  553. define_label($1, & $$);
  554. a_delete $1;
  555. }
  556. | '{'
  557. {
  558. $<state>$.x = current_position.x;
  559. $<state>$.y = current_position.y;
  560. $<state>$.dir = current_direction;
  561. }
  562. element_list '}'
  563. {
  564. current_position.x = $<state>2.x;
  565. current_position.y = $<state>2.y;
  566. current_direction = $<state>2.dir;
  567. }
  568. optional_element
  569. {
  570. $$ = $3;
  571. }
  572. | placeless_element
  573. {
  574. $$.obj = 0;
  575. $$.x = current_position.x;
  576. $$.y = current_position.y;
  577. }
  578. ;
  579. optional_element:
  580. /* empty */
  581. {}
  582. | element
  583. {}
  584. ;
  585. object_spec:
  586. BOX
  587. { $$ = new object_spec(BOX_OBJECT); }
  588. | CIRCLE
  589. { $$ = new object_spec(CIRCLE_OBJECT); }
  590. | ELLIPSE
  591. { $$ = new object_spec(ELLIPSE_OBJECT); }
  592. | ARC
  593. {
  594. $$ = new object_spec(ARC_OBJECT);
  595. $$->dir = current_direction;
  596. }
  597. | LINE
  598. {
  599. $$ = new object_spec(LINE_OBJECT);
  600. lookup_variable("lineht", & $$->segment_height);
  601. lookup_variable("linewid", & $$->segment_width);
  602. $$->dir = current_direction;
  603. }
  604. | ARROW
  605. {
  606. $$ = new object_spec(ARROW_OBJECT);
  607. lookup_variable("lineht", & $$->segment_height);
  608. lookup_variable("linewid", & $$->segment_width);
  609. $$->dir = current_direction;
  610. }
  611. | MOVE
  612. {
  613. $$ = new object_spec(MOVE_OBJECT);
  614. lookup_variable("moveht", & $$->segment_height);
  615. lookup_variable("movewid", & $$->segment_width);
  616. $$->dir = current_direction;
  617. }
  618. | SPLINE
  619. {
  620. $$ = new object_spec(SPLINE_OBJECT);
  621. lookup_variable("lineht", & $$->segment_height);
  622. lookup_variable("linewid", & $$->segment_width);
  623. $$->dir = current_direction;
  624. }
  625. | text %prec TEXT
  626. {
  627. $$ = new object_spec(TEXT_OBJECT);
  628. $$->text = new text_item($1.str, $1.filename, $1.lineno);
  629. }
  630. | PLOT expr
  631. {
  632. $$ = new object_spec(TEXT_OBJECT);
  633. $$->text = new text_item(format_number(0, $2), 0, -1);
  634. }
  635. | PLOT expr text
  636. {
  637. $$ = new object_spec(TEXT_OBJECT);
  638. $$->text = new text_item(format_number($3.str, $2),
  639. $3.filename, $3.lineno);
  640. a_delete $3.str;
  641. }
  642. | '['
  643. {
  644. saved_state *p = new saved_state;
  645. $<pstate>$ = p;
  646. p->x = current_position.x;
  647. p->y = current_position.y;
  648. p->dir = current_direction;
  649. p->tbl = current_table;
  650. p->prev = current_saved_state;
  651. current_position.x = 0.0;
  652. current_position.y = 0.0;
  653. current_table = new PTABLE(place);
  654. current_saved_state = p;
  655. olist.append(make_mark_object());
  656. }
  657. element_list ']'
  658. {
  659. current_position.x = $<pstate>2->x;
  660. current_position.y = $<pstate>2->y;
  661. current_direction = $<pstate>2->dir;
  662. $$ = new object_spec(BLOCK_OBJECT);
  663. olist.wrap_up_block(& $$->oblist);
  664. $$->tbl = current_table;
  665. current_table = $<pstate>2->tbl;
  666. current_saved_state = $<pstate>2->prev;
  667. delete $<pstate>2;
  668. }
  669. | object_spec HEIGHT expr
  670. {
  671. $$ = $1;
  672. $$->height = $3;
  673. $$->flags |= HAS_HEIGHT;
  674. }
  675. | object_spec RADIUS expr
  676. {
  677. $$ = $1;
  678. $$->radius = $3;
  679. $$->flags |= HAS_RADIUS;
  680. }
  681. | object_spec WIDTH expr
  682. {
  683. $$ = $1;
  684. $$->width = $3;
  685. $$->flags |= HAS_WIDTH;
  686. }
  687. | object_spec DIAMETER expr
  688. {
  689. $$ = $1;
  690. $$->radius = $3/2.0;
  691. $$->flags |= HAS_RADIUS;
  692. }
  693. | object_spec expr %prec HEIGHT
  694. {
  695. $$ = $1;
  696. $$->flags |= HAS_SEGMENT;
  697. switch ($$->dir) {
  698. case UP_DIRECTION:
  699. $$->segment_pos.y += $2;
  700. break;
  701. case DOWN_DIRECTION:
  702. $$->segment_pos.y -= $2;
  703. break;
  704. case RIGHT_DIRECTION:
  705. $$->segment_pos.x += $2;
  706. break;
  707. case LEFT_DIRECTION:
  708. $$->segment_pos.x -= $2;
  709. break;
  710. }
  711. }
  712. | object_spec UP
  713. {
  714. $$ = $1;
  715. $$->dir = UP_DIRECTION;
  716. $$->flags |= HAS_SEGMENT;
  717. $$->segment_pos.y += $$->segment_height;
  718. }
  719. | object_spec UP expr
  720. {
  721. $$ = $1;
  722. $$->dir = UP_DIRECTION;
  723. $$->flags |= HAS_SEGMENT;
  724. $$->segment_pos.y += $3;
  725. }
  726. | object_spec DOWN
  727. {
  728. $$ = $1;
  729. $$->dir = DOWN_DIRECTION;
  730. $$->flags |= HAS_SEGMENT;
  731. $$->segment_pos.y -= $$->segment_height;
  732. }
  733. | object_spec DOWN expr
  734. {
  735. $$ = $1;
  736. $$->dir = DOWN_DIRECTION;
  737. $$->flags |= HAS_SEGMENT;
  738. $$->segment_pos.y -= $3;
  739. }
  740. | object_spec RIGHT
  741. {
  742. $$ = $1;
  743. $$->dir = RIGHT_DIRECTION;
  744. $$->flags |= HAS_SEGMENT;
  745. $$->segment_pos.x += $$->segment_width;
  746. }
  747. | object_spec RIGHT expr
  748. {
  749. $$ = $1;
  750. $$->dir = RIGHT_DIRECTION;
  751. $$->flags |= HAS_SEGMENT;
  752. $$->segment_pos.x += $3;
  753. }
  754. | object_spec LEFT
  755. {
  756. $$ = $1;
  757. $$->dir = LEFT_DIRECTION;
  758. $$->flags |= HAS_SEGMENT;
  759. $$->segment_pos.x -= $$->segment_width;
  760. }
  761. | object_spec LEFT expr
  762. {
  763. $$ = $1;
  764. $$->dir = LEFT_DIRECTION;
  765. $$->flags |= HAS_SEGMENT;
  766. $$->segment_pos.x -= $3;
  767. }
  768. | object_spec FROM position
  769. {
  770. $$ = $1;
  771. $$->flags |= HAS_FROM;
  772. $$->from.x = $3.x;
  773. $$->from.y = $3.y;
  774. }
  775. | object_spec TO position
  776. {
  777. $$ = $1;
  778. if ($$->flags & HAS_SEGMENT)
  779. $$->segment_list = new segment($$->segment_pos,
  780. $$->segment_is_absolute,
  781. $$->segment_list);
  782. $$->flags |= HAS_SEGMENT;
  783. $$->segment_pos.x = $3.x;
  784. $$->segment_pos.y = $3.y;
  785. $$->segment_is_absolute = 1;
  786. $$->flags |= HAS_TO;
  787. $$->to.x = $3.x;
  788. $$->to.y = $3.y;
  789. }
  790. | object_spec AT position
  791. {
  792. $$ = $1;
  793. $$->flags |= HAS_AT;
  794. $$->at.x = $3.x;
  795. $$->at.y = $3.y;
  796. if ($$->type != ARC_OBJECT) {
  797. $$->flags |= HAS_FROM;
  798. $$->from.x = $3.x;
  799. $$->from.y = $3.y;
  800. }
  801. }
  802. | object_spec WITH path
  803. {
  804. $$ = $1;
  805. $$->flags |= HAS_WITH;
  806. $$->with = $3;
  807. }
  808. | object_spec WITH position %prec ','
  809. {
  810. $$ = $1;
  811. $$->flags |= HAS_WITH;
  812. position pos;
  813. pos.x = $3.x;
  814. pos.y = $3.y;
  815. $$->with = new path(pos);
  816. }
  817. | object_spec BY expr_pair
  818. {
  819. $$ = $1;
  820. $$->flags |= HAS_SEGMENT;
  821. $$->segment_pos.x += $3.x;
  822. $$->segment_pos.y += $3.y;
  823. }
  824. | object_spec THEN
  825. {
  826. $$ = $1;
  827. if ($$->flags & HAS_SEGMENT) {
  828. $$->segment_list = new segment($$->segment_pos,
  829. $$->segment_is_absolute,
  830. $$->segment_list);
  831. $$->flags &= ~HAS_SEGMENT;
  832. $$->segment_pos.x = $$->segment_pos.y = 0.0;
  833. $$->segment_is_absolute = 0;
  834. }
  835. }
  836. | object_spec SOLID
  837. {
  838. $$ = $1; // nothing
  839. }
  840. | object_spec DOTTED
  841. {
  842. $$ = $1;
  843. $$->flags |= IS_DOTTED;
  844. lookup_variable("dashwid", & $$->dash_width);
  845. }
  846. | object_spec DOTTED expr
  847. {
  848. $$ = $1;
  849. $$->flags |= IS_DOTTED;
  850. $$->dash_width = $3;
  851. }
  852. | object_spec DASHED
  853. {
  854. $$ = $1;
  855. $$->flags |= IS_DASHED;
  856. lookup_variable("dashwid", & $$->dash_width);
  857. }
  858. | object_spec DASHED expr
  859. {
  860. $$ = $1;
  861. $$->flags |= IS_DASHED;
  862. $$->dash_width = $3;
  863. }
  864. | object_spec FILL
  865. {
  866. $$ = $1;
  867. $$->flags |= IS_DEFAULT_FILLED;
  868. }
  869. | object_spec FILL expr
  870. {
  871. $$ = $1;
  872. $$->flags |= IS_FILLED;
  873. $$->fill = $3;
  874. }
  875. | object_spec SHADED text
  876. {
  877. $$ = $1;
  878. $$->flags |= (IS_SHADED | IS_FILLED);
  879. $$->shaded = new char[strlen($3.str)+1];
  880. strcpy($$->shaded, $3.str);
  881. }
  882. | object_spec COLORED text
  883. {
  884. $$ = $1;
  885. $$->flags |= (IS_SHADED | IS_OUTLINED | IS_FILLED);
  886. $$->shaded = new char[strlen($3.str)+1];
  887. strcpy($$->shaded, $3.str);
  888. $$->outlined = new char[strlen($3.str)+1];
  889. strcpy($$->outlined, $3.str);
  890. }
  891. | object_spec OUTLINED text
  892. {
  893. $$ = $1;
  894. $$->flags |= IS_OUTLINED;
  895. $$->outlined = new char[strlen($3.str)+1];
  896. strcpy($$->outlined, $3.str);
  897. }
  898. | object_spec CHOP
  899. {
  900. $$ = $1;
  901. // line chop chop means line chop 0 chop 0
  902. if ($$->flags & IS_DEFAULT_CHOPPED) {
  903. $$->flags |= IS_CHOPPED;
  904. $$->flags &= ~IS_DEFAULT_CHOPPED;
  905. $$->start_chop = $$->end_chop = 0.0;
  906. }
  907. else if ($$->flags & IS_CHOPPED) {
  908. $$->end_chop = 0.0;
  909. }
  910. else {
  911. $$->flags |= IS_DEFAULT_CHOPPED;
  912. }
  913. }
  914. | object_spec CHOP expr
  915. {
  916. $$ = $1;
  917. if ($$->flags & IS_DEFAULT_CHOPPED) {
  918. $$->flags |= IS_CHOPPED;
  919. $$->flags &= ~IS_DEFAULT_CHOPPED;
  920. $$->start_chop = 0.0;
  921. $$->end_chop = $3;
  922. }
  923. else if ($$->flags & IS_CHOPPED) {
  924. $$->end_chop = $3;
  925. }
  926. else {
  927. $$->start_chop = $$->end_chop = $3;
  928. $$->flags |= IS_CHOPPED;
  929. }
  930. }
  931. | object_spec SAME
  932. {
  933. $$ = $1;
  934. $$->flags |= IS_SAME;
  935. }
  936. | object_spec INVISIBLE
  937. {
  938. $$ = $1;
  939. $$->flags |= IS_INVISIBLE;
  940. }
  941. | object_spec LEFT_ARROW_HEAD
  942. {
  943. $$ = $1;
  944. $$->flags |= HAS_LEFT_ARROW_HEAD;
  945. }
  946. | object_spec RIGHT_ARROW_HEAD
  947. {
  948. $$ = $1;
  949. $$->flags |= HAS_RIGHT_ARROW_HEAD;
  950. }
  951. | object_spec DOUBLE_ARROW_HEAD
  952. {
  953. $$ = $1;
  954. $$->flags |= (HAS_LEFT_ARROW_HEAD|HAS_RIGHT_ARROW_HEAD);
  955. }
  956. | object_spec CW
  957. {
  958. $$ = $1;
  959. $$->flags |= IS_CLOCKWISE;
  960. }
  961. | object_spec CCW
  962. {
  963. $$ = $1;
  964. $$->flags &= ~IS_CLOCKWISE;
  965. }
  966. | object_spec text %prec TEXT
  967. {
  968. $$ = $1;
  969. text_item **p;
  970. for (p = & $$->text; *p; p = &(*p)->next)
  971. ;
  972. *p = new text_item($2.str, $2.filename, $2.lineno);
  973. }
  974. | object_spec LJUST
  975. {
  976. $$ = $1;
  977. if ($$->text) {
  978. text_item *p;
  979. for (p = $$->text; p->next; p = p->next)
  980. ;
  981. p->adj.h = LEFT_ADJUST;
  982. }
  983. }
  984. | object_spec RJUST
  985. {
  986. $$ = $1;
  987. if ($$->text) {
  988. text_item *p;
  989. for (p = $$->text; p->next; p = p->next)
  990. ;
  991. p->adj.h = RIGHT_ADJUST;
  992. }
  993. }
  994. | object_spec ABOVE
  995. {
  996. $$ = $1;
  997. if ($$->text) {
  998. text_item *p;
  999. for (p = $$->text; p->next; p = p->next)
  1000. ;
  1001. p->adj.v = ABOVE_ADJUST;
  1002. }
  1003. }
  1004. | object_spec BELOW
  1005. {
  1006. $$ = $1;
  1007. if ($$->text) {
  1008. text_item *p;
  1009. for (p = $$->text; p->next; p = p->next)
  1010. ;
  1011. p->adj.v = BELOW_ADJUST;
  1012. }
  1013. }
  1014. | object_spec THICKNESS expr
  1015. {
  1016. $$ = $1;
  1017. $$->flags |= HAS_THICKNESS;
  1018. $$->thickness = $3;
  1019. }
  1020. | object_spec ALIGNED
  1021. {
  1022. $$ = $1;
  1023. $$->flags |= IS_ALIGNED;
  1024. }
  1025. ;
  1026. text:
  1027. TEXT
  1028. { $$ = $1; }
  1029. | SPRINTF '(' TEXT sprintf_args ')'
  1030. {
  1031. $$.filename = $3.filename;
  1032. $$.lineno = $3.lineno;
  1033. $$.str = do_sprintf($3.str, $4.v, $4.nv);
  1034. a_delete $4.v;
  1035. a_delete $3.str;
  1036. }
  1037. ;
  1038. sprintf_args:
  1039. /* empty */
  1040. {
  1041. $$.v = 0;
  1042. $$.nv = 0;
  1043. $$.maxv = 0;
  1044. }
  1045. | sprintf_args ',' expr
  1046. {
  1047. $$ = $1;
  1048. if ($$.nv >= $$.maxv) {
  1049. if ($$.nv == 0) {
  1050. $$.v = new double[4];
  1051. $$.maxv = 4;
  1052. }
  1053. else {
  1054. double *oldv = $$.v;
  1055. $$.maxv *= 2;
  1056. #if 0
  1057. $$.v = new double[$$.maxv];
  1058. memcpy($$.v, oldv, $$.nv*sizeof(double));
  1059. #else
  1060. // workaround for bug in Compaq C++ V6.5-033
  1061. // for Compaq Tru64 UNIX V5.1A (Rev. 1885)
  1062. double *foo = new double[$$.maxv];
  1063. memcpy(foo, oldv, $$.nv*sizeof(double));
  1064. $$.v = foo;
  1065. #endif
  1066. a_delete oldv;
  1067. }
  1068. }
  1069. $$.v[$$.nv] = $3;
  1070. $$.nv += 1;
  1071. }
  1072. ;
  1073. position:
  1074. position_not_place
  1075. { $$ = $1; }
  1076. | place
  1077. {
  1078. position pos = $1;
  1079. $$.x = pos.x;
  1080. $$.y = pos.y;
  1081. }
  1082. | '(' place ')'
  1083. {
  1084. position pos = $2;
  1085. $$.x = pos.x;
  1086. $$.y = pos.y;
  1087. }
  1088. ;
  1089. position_not_place:
  1090. expr_pair
  1091. { $$ = $1; }
  1092. | position '+' expr_pair
  1093. {
  1094. $$.x = $1.x + $3.x;
  1095. $$.y = $1.y + $3.y;
  1096. }
  1097. | '(' position '+' expr_pair ')'
  1098. {
  1099. $$.x = $2.x + $4.x;
  1100. $$.y = $2.y + $4.y;
  1101. }
  1102. | position '-' expr_pair
  1103. {
  1104. $$.x = $1.x - $3.x;
  1105. $$.y = $1.y - $3.y;
  1106. }
  1107. | '(' position '-' expr_pair ')'
  1108. {
  1109. $$.x = $2.x - $4.x;
  1110. $$.y = $2.y - $4.y;
  1111. }
  1112. | '(' position ',' position ')'
  1113. {
  1114. $$.x = $2.x;
  1115. $$.y = $4.y;
  1116. }
  1117. | expr between position AND position
  1118. {
  1119. $$.x = (1.0 - $1)*$3.x + $1*$5.x;
  1120. $$.y = (1.0 - $1)*$3.y + $1*$5.y;
  1121. }
  1122. | '(' expr between position AND position ')'
  1123. {
  1124. $$.x = (1.0 - $2)*$4.x + $2*$6.x;
  1125. $$.y = (1.0 - $2)*$4.y + $2*$6.y;
  1126. }
  1127. | expr '<' position ',' position '>'
  1128. {
  1129. $$.x = (1.0 - $1)*$3.x + $1*$5.x;
  1130. $$.y = (1.0 - $1)*$3.y + $1*$5.y;
  1131. }
  1132. | '(' expr '<' position ',' position '>' ')'
  1133. {
  1134. $$.x = (1.0 - $2)*$4.x + $2*$6.x;
  1135. $$.y = (1.0 - $2)*$4.y + $2*$6.y;
  1136. }
  1137. ;
  1138. between:
  1139. BETWEEN
  1140. | OF THE WAY BETWEEN
  1141. ;
  1142. expr_pair:
  1143. expr ',' expr
  1144. {
  1145. $$.x = $1;
  1146. $$.y = $3;
  1147. }
  1148. | '(' expr_pair ')'
  1149. { $$ = $2; }
  1150. ;
  1151. place:
  1152. /* line at A left == line (at A) left */
  1153. label %prec CHOP
  1154. { $$ = $1; }
  1155. | label corner
  1156. {
  1157. path pth($2);
  1158. if (!pth.follow($1, & $$))
  1159. YYABORT;
  1160. }
  1161. | corner label
  1162. {
  1163. path pth($1);
  1164. if (!pth.follow($2, & $$))
  1165. YYABORT;
  1166. }
  1167. | corner OF label
  1168. {
  1169. path pth($1);
  1170. if (!pth.follow($3, & $$))
  1171. YYABORT;
  1172. }
  1173. | HERE
  1174. {
  1175. $$.x = current_position.x;
  1176. $$.y = current_position.y;
  1177. $$.obj = 0;
  1178. }
  1179. ;
  1180. label:
  1181. LABEL
  1182. {
  1183. place *p = lookup_label($1);
  1184. if (!p) {
  1185. lex_error("there is no place `%1'", $1);
  1186. YYABORT;
  1187. }
  1188. $$ = *p;
  1189. a_delete $1;
  1190. }
  1191. | nth_primitive
  1192. { $$.obj = $1; }
  1193. | label '.' LABEL
  1194. {
  1195. path pth($3);
  1196. if (!pth.follow($1, & $$))
  1197. YYABORT;
  1198. }
  1199. ;
  1200. ordinal:
  1201. ORDINAL
  1202. { $$ = $1; }
  1203. | '`' any_expr TH
  1204. {
  1205. // XXX Check for overflow (and non-integers?).
  1206. $$ = (int)$2;
  1207. }
  1208. ;
  1209. optional_ordinal_last:
  1210. LAST
  1211. { $$ = 1; }
  1212. | ordinal LAST
  1213. { $$ = $1; }
  1214. ;
  1215. nth_primitive:
  1216. ordinal object_type
  1217. {
  1218. int count = 0;
  1219. object *p;
  1220. for (p = olist.head; p != 0; p = p->next)
  1221. if (p->type() == $2 && ++count == $1) {
  1222. $$ = p;
  1223. break;
  1224. }
  1225. if (p == 0) {
  1226. lex_error("there is no %1%2 %3", $1, ordinal_postfix($1),
  1227. object_type_name($2));
  1228. YYABORT;
  1229. }
  1230. }
  1231. | optional_ordinal_last object_type
  1232. {
  1233. int count = 0;
  1234. object *p;
  1235. for (p = olist.tail; p != 0; p = p->prev)
  1236. if (p->type() == $2 && ++count == $1) {
  1237. $$ = p;
  1238. break;
  1239. }
  1240. if (p == 0) {
  1241. lex_error("there is no %1%2 last %3", $1,
  1242. ordinal_postfix($1), object_type_name($2));
  1243. YYABORT;
  1244. }
  1245. }
  1246. ;
  1247. object_type:
  1248. BOX
  1249. { $$ = BOX_OBJECT; }
  1250. | CIRCLE
  1251. { $$ = CIRCLE_OBJECT; }
  1252. | ELLIPSE
  1253. { $$ = ELLIPSE_OBJECT; }
  1254. | ARC
  1255. { $$ = ARC_OBJECT; }
  1256. | LINE
  1257. { $$ = LINE_OBJECT; }
  1258. | ARROW
  1259. { $$ = ARROW_OBJECT; }
  1260. | SPLINE
  1261. { $$ = SPLINE_OBJECT; }
  1262. | '[' ']'
  1263. { $$ = BLOCK_OBJECT; }
  1264. | TEXT
  1265. { $$ = TEXT_OBJECT; }
  1266. ;
  1267. label_path:
  1268. '.' LABEL
  1269. { $$ = new path($2); }
  1270. | label_path '.' LABEL
  1271. {
  1272. $$ = $1;
  1273. $$->append($3);
  1274. }
  1275. ;
  1276. relative_path:
  1277. corner %prec CHOP
  1278. { $$ = new path($1); }
  1279. /* give this a lower precedence than LEFT and RIGHT so that
  1280. [A: box] with .A left == [A: box] with (.A left) */
  1281. | label_path %prec TEXT
  1282. { $$ = $1; }
  1283. | label_path corner
  1284. {
  1285. $$ = $1;
  1286. $$->append($2);
  1287. }
  1288. ;
  1289. path:
  1290. relative_path
  1291. { $$ = $1; }
  1292. | '(' relative_path ',' relative_path ')'
  1293. {
  1294. $$ = $2;
  1295. $$->set_ypath($4);
  1296. }
  1297. /* The rest of these rules are a compatibility sop. */
  1298. | ORDINAL LAST object_type relative_path
  1299. {
  1300. lex_warning("`%1%2 last %3' in `with' argument ignored",
  1301. $1, ordinal_postfix($1), object_type_name($3));
  1302. $$ = $4;
  1303. }
  1304. | LAST object_type relative_path
  1305. {
  1306. lex_warning("`last %1' in `with' argument ignored",
  1307. object_type_name($2));
  1308. $$ = $3;
  1309. }
  1310. | ORDINAL object_type relative_path
  1311. {
  1312. lex_warning("`%1%2 %3' in `with' argument ignored",
  1313. $1, ordinal_postfix($1), object_type_name($2));
  1314. $$ = $3;
  1315. }
  1316. | LABEL relative_path
  1317. {
  1318. lex_warning("initial `%1' in `with' argument ignored", $1);
  1319. a_delete $1;
  1320. $$ = $2;
  1321. }
  1322. ;
  1323. corner:
  1324. DOT_N
  1325. { $$ = &object::north; }
  1326. | DOT_E
  1327. { $$ = &object::east; }
  1328. | DOT_W
  1329. { $$ = &object::west; }
  1330. | DOT_S
  1331. { $$ = &object::south; }
  1332. | DOT_NE
  1333. { $$ = &object::north_east; }
  1334. | DOT_SE
  1335. { $$ = &object:: south_east; }
  1336. | DOT_NW
  1337. { $$ = &object::north_west; }
  1338. | DOT_SW
  1339. { $$ = &object::south_west; }
  1340. | DOT_C
  1341. { $$ = &object::center; }
  1342. | DOT_START
  1343. { $$ = &object::start; }
  1344. | DOT_END
  1345. { $$ = &object::end; }
  1346. | TOP
  1347. { $$ = &object::north; }
  1348. | BOTTOM
  1349. { $$ = &object::south; }
  1350. | LEFT
  1351. { $$ = &object::west; }
  1352. | RIGHT
  1353. { $$ = &object::east; }
  1354. | UPPER LEFT
  1355. { $$ = &object::north_west; }
  1356. | LOWER LEFT
  1357. { $$ = &object::south_west; }
  1358. | UPPER RIGHT
  1359. { $$ = &object::north_east; }
  1360. | LOWER RIGHT
  1361. { $$ = &object::south_east; }
  1362. | LEFT_CORNER
  1363. { $$ = &object::west; }
  1364. | RIGHT_CORNER
  1365. { $$ = &object::east; }
  1366. | UPPER LEFT_CORNER
  1367. { $$ = &object::north_west; }
  1368. | LOWER LEFT_CORNER
  1369. { $$ = &object::south_west; }
  1370. | UPPER RIGHT_CORNER
  1371. { $$ = &object::north_east; }
  1372. | LOWER RIGHT_CORNER
  1373. { $$ = &object::south_east; }
  1374. | NORTH
  1375. { $$ = &object::north; }
  1376. | SOUTH
  1377. { $$ = &object::south; }
  1378. | EAST
  1379. { $$ = &object::east; }
  1380. | WEST
  1381. { $$ = &object::west; }
  1382. | CENTER
  1383. { $$ = &object::center; }
  1384. | START
  1385. { $$ = &object::start; }
  1386. | END
  1387. { $$ = &object::end; }
  1388. ;
  1389. expr:
  1390. VARIABLE
  1391. {
  1392. if (!lookup_variable($1, & $$)) {
  1393. lex_error("there is no variable `%1'", $1);
  1394. YYABORT;
  1395. }
  1396. a_delete $1;
  1397. }
  1398. | NUMBER
  1399. { $$ = $1; }
  1400. | place DOT_X
  1401. {
  1402. if ($1.obj != 0)
  1403. $$ = $1.obj->origin().x;
  1404. else
  1405. $$ = $1.x;
  1406. }
  1407. | place DOT_Y
  1408. {
  1409. if ($1.obj != 0)
  1410. $$ = $1.obj->origin().y;
  1411. else
  1412. $$ = $1.y;
  1413. }
  1414. | place DOT_HT
  1415. {
  1416. if ($1.obj != 0)
  1417. $$ = $1.obj->height();
  1418. else
  1419. $$ = 0.0;
  1420. }
  1421. | place DOT_WID
  1422. {
  1423. if ($1.obj != 0)
  1424. $$ = $1.obj->width();
  1425. else
  1426. $$ = 0.0;
  1427. }
  1428. | place DOT_RAD
  1429. {
  1430. if ($1.obj != 0)
  1431. $$ = $1.obj->radius();
  1432. else
  1433. $$ = 0.0;
  1434. }
  1435. | expr '+' expr
  1436. { $$ = $1 + $3; }
  1437. | expr '-' expr
  1438. { $$ = $1 - $3; }
  1439. | expr '*' expr
  1440. { $$ = $1 * $3; }
  1441. | expr '/' expr
  1442. {
  1443. if ($3 == 0.0) {
  1444. lex_error("division by zero");
  1445. YYABORT;
  1446. }
  1447. $$ = $1/$3;
  1448. }
  1449. | expr '%' expr
  1450. {
  1451. if ($3 == 0.0) {
  1452. lex_error("modulus by zero");
  1453. YYABORT;
  1454. }
  1455. $$ = fmod($1, $3);
  1456. }
  1457. | expr '^' expr
  1458. {
  1459. errno = 0;
  1460. $$ = pow($1, $3);
  1461. if (errno == EDOM) {
  1462. lex_error("arguments to `^' operator out of domain");
  1463. YYABORT;
  1464. }
  1465. if (errno == ERANGE) {
  1466. lex_error("result of `^' operator out of range");
  1467. YYABORT;
  1468. }
  1469. }
  1470. | '-' expr %prec '!'
  1471. { $$ = -$2; }
  1472. | '(' any_expr ')'
  1473. { $$ = $2; }
  1474. | SIN '(' any_expr ')'
  1475. {
  1476. errno = 0;
  1477. $$ = sin($3);
  1478. if (errno == ERANGE) {
  1479. lex_error("sin result out of range");
  1480. YYABORT;
  1481. }
  1482. }
  1483. | COS '(' any_expr ')'
  1484. {
  1485. errno = 0;
  1486. $$ = cos($3);
  1487. if (errno == ERANGE) {
  1488. lex_error("cos result out of range");
  1489. YYABORT;
  1490. }
  1491. }
  1492. | ATAN2 '(' any_expr ',' any_expr ')'
  1493. {
  1494. errno = 0;
  1495. $$ = atan2($3, $5);
  1496. if (errno == EDOM) {
  1497. lex_error("atan2 argument out of domain");
  1498. YYABORT;
  1499. }
  1500. if (errno == ERANGE) {
  1501. lex_error("atan2 result out of range");
  1502. YYABORT;
  1503. }
  1504. }
  1505. | LOG '(' any_expr ')'
  1506. {
  1507. errno = 0;
  1508. $$ = log10($3);
  1509. if (errno == ERANGE) {
  1510. lex_error("log result out of range");
  1511. YYABORT;
  1512. }
  1513. }
  1514. | EXP '(' any_expr ')'
  1515. {
  1516. errno = 0;
  1517. $$ = pow(10.0, $3);
  1518. if (errno == ERANGE) {
  1519. lex_error("exp result out of range");
  1520. YYABORT;
  1521. }
  1522. }
  1523. | SQRT '(' any_expr ')'
  1524. {
  1525. errno = 0;
  1526. $$ = sqrt($3);
  1527. if (errno == EDOM) {
  1528. lex_error("sqrt argument out of domain");
  1529. YYABORT;
  1530. }
  1531. }
  1532. | K_MAX '(' any_expr ',' any_expr ')'
  1533. { $$ = $3 > $5 ? $3 : $5; }
  1534. | K_MIN '(' any_expr ',' any_expr ')'
  1535. { $$ = $3 < $5 ? $3 : $5; }
  1536. | INT '(' any_expr ')'
  1537. { $$ = floor($3); }
  1538. | RAND '(' any_expr ')'
  1539. { $$ = 1.0 + floor(((rand()&0x7fff)/double(0x7fff))*$3); }
  1540. | RAND '(' ')'
  1541. {
  1542. /* return a random number in the range [0,1) */
  1543. /* portable, but not very random */
  1544. $$ = (rand() & 0x7fff) / double(0x8000);
  1545. }
  1546. | SRAND '(' any_expr ')'
  1547. {
  1548. $$ = 0;
  1549. srand((unsigned int)$3);
  1550. }
  1551. | expr '<' expr
  1552. { $$ = ($1 < $3); }
  1553. | expr LESSEQUAL expr
  1554. { $$ = ($1 <= $3); }
  1555. | expr '>' expr
  1556. { $$ = ($1 > $3); }
  1557. | expr GREATEREQUAL expr
  1558. { $$ = ($1 >= $3); }
  1559. | expr EQUALEQUAL expr
  1560. { $$ = ($1 == $3); }
  1561. | expr NOTEQUAL expr
  1562. { $$ = ($1 != $3); }
  1563. | expr ANDAND expr
  1564. { $$ = ($1 != 0.0 && $3 != 0.0); }
  1565. | expr OROR expr
  1566. { $$ = ($1 != 0.0 || $3 != 0.0); }
  1567. | '!' expr
  1568. { $$ = ($2 == 0.0); }
  1569. ;
  1570. %%
  1571. /* bison defines const to be empty unless __STDC__ is defined, which it
  1572. isn't under cfront */
  1573. #ifdef const
  1574. #undef const
  1575. #endif
  1576. static struct {
  1577. const char *name;
  1578. double val;
  1579. int scaled; // non-zero if val should be multiplied by scale
  1580. } defaults_table[] = {
  1581. { "arcrad", .25, 1 },
  1582. { "arrowht", .1, 1 },
  1583. { "arrowwid", .05, 1 },
  1584. { "circlerad", .25, 1 },
  1585. { "boxht", .5, 1 },
  1586. { "boxwid", .75, 1 },
  1587. { "boxrad", 0.0, 1 },
  1588. { "dashwid", .05, 1 },
  1589. { "ellipseht", .5, 1 },
  1590. { "ellipsewid", .75, 1 },
  1591. { "moveht", .5, 1 },
  1592. { "movewid", .5, 1 },
  1593. { "lineht", .5, 1 },
  1594. { "linewid", .5, 1 },
  1595. { "textht", 0.0, 1 },
  1596. { "textwid", 0.0, 1 },
  1597. { "scale", 1.0, 0 },
  1598. { "linethick", -1.0, 0 }, // in points
  1599. { "fillval", .5, 0 },
  1600. { "arrowhead", 1.0, 0 },
  1601. { "maxpswid", 8.5, 0 },
  1602. { "maxpsht", 11.0, 0 },
  1603. };
  1604. place *lookup_label(const char *label)
  1605. {
  1606. saved_state *state = current_saved_state;
  1607. PTABLE(place) *tbl = current_table;
  1608. for (;;) {
  1609. place *pl = tbl->lookup(label);
  1610. if (pl)
  1611. return pl;
  1612. if (!state)
  1613. return 0;
  1614. tbl = state->tbl;
  1615. state = state->prev;
  1616. }
  1617. }
  1618. void define_label(const char *label, const place *pl)
  1619. {
  1620. place *p = new place[1];
  1621. *p = *pl;
  1622. current_table->define(label, p);
  1623. }
  1624. int lookup_variable(const char *name, double *val)
  1625. {
  1626. place *pl = lookup_label(name);
  1627. if (pl) {
  1628. *val = pl->x;
  1629. return 1;
  1630. }
  1631. return 0;
  1632. }
  1633. void define_variable(const char *name, double val)
  1634. {
  1635. place *p = new place[1];
  1636. p->obj = 0;
  1637. p->x = val;
  1638. p->y = 0.0;
  1639. current_table->define(name, p);
  1640. if (strcmp(name, "scale") == 0) {
  1641. // When the scale changes, reset all scaled pre-defined variables to
  1642. // their default values.
  1643. for (unsigned int i = 0;
  1644. i < sizeof(defaults_table)/sizeof(defaults_table[0]); i++)
  1645. if (defaults_table[i].scaled)
  1646. define_variable(defaults_table[i].name, val*defaults_table[i].val);
  1647. }
  1648. }
  1649. // called once only (not once per parse)
  1650. void parse_init()
  1651. {
  1652. current_direction = RIGHT_DIRECTION;
  1653. current_position.x = 0.0;
  1654. current_position.y = 0.0;
  1655. // This resets everything to its default value.
  1656. reset_all();
  1657. }
  1658. void reset(const char *nm)
  1659. {
  1660. for (unsigned int i = 0;
  1661. i < sizeof(defaults_table)/sizeof(defaults_table[0]); i++)
  1662. if (strcmp(nm, defaults_table[i].name) == 0) {
  1663. double val = defaults_table[i].val;
  1664. if (defaults_table[i].scaled) {
  1665. double scale;
  1666. lookup_variable("scale", &scale);
  1667. val *= scale;
  1668. }
  1669. define_variable(defaults_table[i].name, val);
  1670. return;
  1671. }
  1672. lex_error("`%1' is not a predefined variable", nm);
  1673. }
  1674. void reset_all()
  1675. {
  1676. // We only have to explicitly reset the pre-defined variables that
  1677. // aren't scaled because `scale' is not scaled, and changing the
  1678. // value of `scale' will reset all the pre-defined variables that
  1679. // are scaled.
  1680. for (unsigned int i = 0;
  1681. i < sizeof(defaults_table)/sizeof(defaults_table[0]); i++)
  1682. if (!defaults_table[i].scaled)
  1683. define_variable(defaults_table[i].name, defaults_table[i].val);
  1684. }
  1685. // called after each parse
  1686. void parse_cleanup()
  1687. {
  1688. while (current_saved_state != 0) {
  1689. delete current_table;
  1690. current_table = current_saved_state->tbl;
  1691. saved_state *tem = current_saved_state;
  1692. current_saved_state = current_saved_state->prev;
  1693. delete tem;
  1694. }
  1695. assert(current_table == &top_table);
  1696. PTABLE_ITERATOR(place) iter(current_table);
  1697. const char *key;
  1698. place *pl;
  1699. while (iter.next(&key, &pl))
  1700. if (pl->obj != 0) {
  1701. position pos = pl->obj->origin();
  1702. pl->obj = 0;
  1703. pl->x = pos.x;
  1704. pl->y = pos.y;
  1705. }
  1706. while (olist.head != 0) {
  1707. object *tem = olist.head;
  1708. olist.head = olist.head->next;
  1709. delete tem;
  1710. }
  1711. olist.tail = 0;
  1712. current_direction = RIGHT_DIRECTION;
  1713. current_position.x = 0.0;
  1714. current_position.y = 0.0;
  1715. }
  1716. const char *ordinal_postfix(int n)
  1717. {
  1718. if (n < 10 || n > 20)
  1719. switch (n % 10) {
  1720. case 1:
  1721. return "st";
  1722. case 2:
  1723. return "nd";
  1724. case 3:
  1725. return "rd";
  1726. }
  1727. return "th";
  1728. }
  1729. const char *object_type_name(object_type type)
  1730. {
  1731. switch (type) {
  1732. case BOX_OBJECT:
  1733. return "box";
  1734. case CIRCLE_OBJECT:
  1735. return "circle";
  1736. case ELLIPSE_OBJECT:
  1737. return "ellipse";
  1738. case ARC_OBJECT:
  1739. return "arc";
  1740. case SPLINE_OBJECT:
  1741. return "spline";
  1742. case LINE_OBJECT:
  1743. return "line";
  1744. case ARROW_OBJECT:
  1745. return "arrow";
  1746. case MOVE_OBJECT:
  1747. return "move";
  1748. case TEXT_OBJECT:
  1749. return "\"\"";
  1750. case BLOCK_OBJECT:
  1751. return "[]";
  1752. case OTHER_OBJECT:
  1753. case MARK_OBJECT:
  1754. default:
  1755. break;
  1756. }
  1757. return "object";
  1758. }
  1759. static char sprintf_buf[1024];
  1760. char *format_number(const char *form, double n)
  1761. {
  1762. if (form == 0)
  1763. form = "%g";
  1764. return do_sprintf(form, &n, 1);
  1765. }
  1766. char *do_sprintf(const char *form, const double *v, int nv)
  1767. {
  1768. string result;
  1769. int i = 0;
  1770. string one_format;
  1771. while (*form) {
  1772. if (*form == '%') {
  1773. one_format += *form++;
  1774. for (; *form != '\0' && strchr("#-+ 0123456789.", *form) != 0; form++)
  1775. one_format += *form;
  1776. if (*form == '\0' || strchr("eEfgG%", *form) == 0) {
  1777. lex_error("bad sprintf format");
  1778. result += one_format;
  1779. result += form;
  1780. break;
  1781. }
  1782. if (*form == '%') {
  1783. one_format += *form++;
  1784. one_format += '\0';
  1785. snprintf(sprintf_buf, sizeof(sprintf_buf),
  1786. "%s", one_format.contents());
  1787. }
  1788. else {
  1789. if (i >= nv) {
  1790. lex_error("too few arguments to snprintf");
  1791. result += one_format;
  1792. result += form;
  1793. break;
  1794. }
  1795. one_format += *form++;
  1796. one_format += '\0';
  1797. snprintf(sprintf_buf, sizeof(sprintf_buf),
  1798. one_format.contents(), v[i++]);
  1799. }
  1800. one_format.clear();
  1801. result += sprintf_buf;
  1802. }
  1803. else
  1804. result += *form++;
  1805. }
  1806. result += '\0';
  1807. return strsave(result.contents());
  1808. }