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