PageRenderTime 69ms CodeModel.GetById 27ms RepoModel.GetById 1ms app.codeStats 0ms

/opensource.apple.com/source/groff/groff-35/groff/src/preproc/pic/pic.y

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