PageRenderTime 64ms CodeModel.GetById 23ms RepoModel.GetById 0ms app.codeStats 1ms

/opensource.apple.com/source/groff/groff-12/groff/pic/pic.y

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