1151497Sru/* Copyright (C) 1989, 1990, 1991, 1992, 2000, 2001, 2002, 2003, 2004, 2005 279543Sru Free Software Foundation, Inc. 375584Sru Written by James Clark (jjc@jclark.com) 475584Sru 575584SruThis file is part of groff. 675584Sru 775584Srugroff is free software; you can redistribute it and/or modify it under 875584Sruthe terms of the GNU General Public License as published by the Free 975584SruSoftware Foundation; either version 2, or (at your option) any later 1075584Sruversion. 1175584Sru 1275584Srugroff is distributed in the hope that it will be useful, but WITHOUT ANY 1375584SruWARRANTY; without even the implied warranty of MERCHANTABILITY or 1475584SruFITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 1575584Srufor more details. 1675584Sru 1775584SruYou should have received a copy of the GNU General Public License along 1875584Sruwith groff; see the file COPYING. If not, write to the Free Software 19151497SruFoundation, 51 Franklin St - Fifth Floor, Boston, MA 02110-1301, USA. */ 2075584Sru%{ 2175584Sru#include "pic.h" 2275584Sru#include "ptable.h" 2375584Sru#include "object.h" 2475584Sru 2575584Sruextern int delim_flag; 2675584Sruextern void copy_rest_thru(const char *, const char *); 2775584Sruextern void copy_file_thru(const char *, const char *, const char *); 2875584Sruextern void push_body(const char *); 2975584Sruextern void do_for(char *var, double from, double to, 3075584Sru int by_is_multiplicative, double by, char *body); 3175584Sruextern void do_lookahead(); 3275584Sru 3375584Sru/* Maximum number of characters produced by printf("%g") */ 3475584Sru#define GDIGITS 14 3575584Sru 3675584Sruint yylex(); 3775584Sruvoid yyerror(const char *); 3875584Sru 3975584Sruvoid reset(const char *nm); 4075584Sruvoid reset_all(); 4175584Sru 4275584Sruplace *lookup_label(const char *); 4375584Sruvoid define_label(const char *label, const place *pl); 4475584Sru 4575584Srudirection current_direction; 4675584Sruposition current_position; 4775584Sru 4875584Sruimplement_ptable(place) 4975584Sru 5075584SruPTABLE(place) top_table; 5175584Sru 5275584SruPTABLE(place) *current_table = &top_table; 5375584Srusaved_state *current_saved_state = 0; 5475584Sru 5575584Sruobject_list olist; 5675584Sru 5775584Sruconst char *ordinal_postfix(int n); 5875584Sruconst char *object_type_name(object_type type); 5975584Sruchar *format_number(const char *form, double n); 6075584Sruchar *do_sprintf(const char *form, const double *v, int nv); 6175584Sru 6275584Sru%} 6375584Sru 6475584Sru 6575584Sru%union { 6675584Sru char *str; 6775584Sru int n; 6875584Sru double x; 6975584Sru struct { double x, y; } pair; 7075584Sru struct { double x; char *body; } if_data; 7175584Sru struct { char *str; const char *filename; int lineno; } lstr; 7275584Sru struct { double *v; int nv; int maxv; } dv; 7375584Sru struct { double val; int is_multiplicative; } by; 7475584Sru place pl; 7575584Sru object *obj; 7675584Sru corner crn; 7775584Sru path *pth; 7875584Sru object_spec *spec; 7975584Sru saved_state *pstate; 8075584Sru graphics_state state; 8175584Sru object_type obtype; 8275584Sru} 8375584Sru 8475584Sru%token <str> LABEL 8575584Sru%token <str> VARIABLE 8675584Sru%token <x> NUMBER 8775584Sru%token <lstr> TEXT 8875584Sru%token <lstr> COMMAND_LINE 8975584Sru%token <str> DELIMITED 9075584Sru%token <n> ORDINAL 9175584Sru%token TH 9275584Sru%token LEFT_ARROW_HEAD 9375584Sru%token RIGHT_ARROW_HEAD 9475584Sru%token DOUBLE_ARROW_HEAD 9575584Sru%token LAST 9675584Sru%token UP 9775584Sru%token DOWN 9875584Sru%token LEFT 9975584Sru%token RIGHT 10075584Sru%token BOX 10175584Sru%token CIRCLE 10275584Sru%token ELLIPSE 10375584Sru%token ARC 10475584Sru%token LINE 10575584Sru%token ARROW 10675584Sru%token MOVE 10775584Sru%token SPLINE 10875584Sru%token HEIGHT 10975584Sru%token RADIUS 110114402Sru%token FIGNAME 11175584Sru%token WIDTH 11275584Sru%token DIAMETER 11375584Sru%token UP 11475584Sru%token DOWN 11575584Sru%token RIGHT 11675584Sru%token LEFT 11775584Sru%token FROM 11875584Sru%token TO 11975584Sru%token AT 12075584Sru%token WITH 12175584Sru%token BY 12275584Sru%token THEN 12375584Sru%token SOLID 12475584Sru%token DOTTED 12575584Sru%token DASHED 12675584Sru%token CHOP 12775584Sru%token SAME 12875584Sru%token INVISIBLE 12975584Sru%token LJUST 13075584Sru%token RJUST 13175584Sru%token ABOVE 13275584Sru%token BELOW 13375584Sru%token OF 13475584Sru%token THE 13575584Sru%token WAY 13675584Sru%token BETWEEN 13775584Sru%token AND 13875584Sru%token HERE 13975584Sru%token DOT_N 14075584Sru%token DOT_E 14175584Sru%token DOT_W 14275584Sru%token DOT_S 14375584Sru%token DOT_NE 14475584Sru%token DOT_SE 14575584Sru%token DOT_NW 14675584Sru%token DOT_SW 14775584Sru%token DOT_C 14875584Sru%token DOT_START 14975584Sru%token DOT_END 15075584Sru%token DOT_X 15175584Sru%token DOT_Y 15275584Sru%token DOT_HT 15375584Sru%token DOT_WID 15475584Sru%token DOT_RAD 15575584Sru%token SIN 15675584Sru%token COS 15775584Sru%token ATAN2 15875584Sru%token LOG 15975584Sru%token EXP 16075584Sru%token SQRT 16175584Sru%token K_MAX 16275584Sru%token K_MIN 16375584Sru%token INT 16475584Sru%token RAND 16575584Sru%token SRAND 16675584Sru%token COPY 16775584Sru%token THRU 16875584Sru%token TOP 16975584Sru%token BOTTOM 17075584Sru%token UPPER 17175584Sru%token LOWER 17275584Sru%token SH 17375584Sru%token PRINT 17475584Sru%token CW 17575584Sru%token CCW 17675584Sru%token FOR 17775584Sru%token DO 17875584Sru%token IF 17975584Sru%token ELSE 18075584Sru%token ANDAND 18175584Sru%token OROR 18275584Sru%token NOTEQUAL 18375584Sru%token EQUALEQUAL 18475584Sru%token LESSEQUAL 18575584Sru%token GREATEREQUAL 18675584Sru%token LEFT_CORNER 18775584Sru%token RIGHT_CORNER 188104862Sru%token NORTH 189104862Sru%token SOUTH 190104862Sru%token EAST 191104862Sru%token WEST 19275584Sru%token CENTER 19375584Sru%token END 19475584Sru%token START 19575584Sru%token RESET 19675584Sru%token UNTIL 19775584Sru%token PLOT 19875584Sru%token THICKNESS 19975584Sru%token FILL 200104862Sru%token COLORED 201104862Sru%token OUTLINED 202104862Sru%token SHADED 20375584Sru%token ALIGNED 20475584Sru%token SPRINTF 20575584Sru%token COMMAND 20675584Sru 20775584Sru%token DEFINE 20875584Sru%token UNDEF 20975584Sru 210104862Sru%left '.' 211104862Sru 21275584Sru/* this ensures that plot 17 "%g" parses as (plot 17 "%g") */ 21375584Sru%left PLOT 21475584Sru%left TEXT SPRINTF 21575584Sru 21675584Sru/* give text adjustments higher precedence than TEXT, so that 21775584Srubox "foo" above ljust == box ("foo" above ljust) 21875584Sru*/ 21975584Sru 22075584Sru%left LJUST RJUST ABOVE BELOW 22175584Sru 22275584Sru%left LEFT RIGHT 22375584Sru/* Give attributes that take an optional expression a higher 22475584Sruprecedence than left and right, so that eg `line chop left' 22575584Sruparses properly. */ 226104862Sru%left CHOP SOLID DASHED DOTTED UP DOWN FILL COLORED OUTLINED 22775584Sru%left LABEL 22875584Sru 22975584Sru%left VARIABLE NUMBER '(' SIN COS ATAN2 LOG EXP SQRT K_MAX K_MIN INT RAND SRAND LAST 23075584Sru%left ORDINAL HERE '`' 23175584Sru 232104862Sru%left BOX CIRCLE ELLIPSE ARC LINE ARROW SPLINE '[' 233104862Sru 23475584Sru/* these need to be lower than '-' */ 23575584Sru%left HEIGHT RADIUS WIDTH DIAMETER FROM TO AT THICKNESS 23675584Sru 23775584Sru/* these must have higher precedence than CHOP so that `label %prec CHOP' 23875584Sruworks */ 23975584Sru%left DOT_N DOT_E DOT_W DOT_S DOT_NE DOT_SE DOT_NW DOT_SW DOT_C 24075584Sru%left DOT_START DOT_END TOP BOTTOM LEFT_CORNER RIGHT_CORNER 241104862Sru%left UPPER LOWER NORTH SOUTH EAST WEST CENTER START END 24275584Sru 24375584Sru%left ',' 24475584Sru%left OROR 24575584Sru%left ANDAND 24675584Sru%left EQUALEQUAL NOTEQUAL 24775584Sru%left '<' '>' LESSEQUAL GREATEREQUAL 24875584Sru 24975584Sru%left BETWEEN OF 25075584Sru%left AND 25175584Sru 25275584Sru%left '+' '-' 25375584Sru%left '*' '/' '%' 25475584Sru%right '!' 25575584Sru%right '^' 25675584Sru 25775584Sru%type <x> expr any_expr text_expr 25875584Sru%type <by> optional_by 25975584Sru%type <pair> expr_pair position_not_place 26075584Sru%type <if_data> simple_if 26175584Sru%type <obj> nth_primitive 26275584Sru%type <crn> corner 26375584Sru%type <pth> path label_path relative_path 26475584Sru%type <pl> place label element element_list middle_element_list 26575584Sru%type <spec> object_spec 26675584Sru%type <pair> position 26775584Sru%type <obtype> object_type 26875584Sru%type <n> optional_ordinal_last ordinal 269114402Sru%type <str> macro_name until 27075584Sru%type <dv> sprintf_args 27175584Sru%type <lstr> text print_args print_arg 27275584Sru 27375584Sru%% 27475584Sru 27575584Srutop: 27675584Sru optional_separator 27775584Sru | element_list 27875584Sru { 27975584Sru if (olist.head) 28075584Sru print_picture(olist.head); 28175584Sru } 28275584Sru ; 28375584Sru 28475584Sru 28575584Sruelement_list: 28675584Sru optional_separator middle_element_list optional_separator 28775584Sru { $$ = $2; } 28875584Sru ; 28975584Sru 29075584Srumiddle_element_list: 29175584Sru element 29275584Sru { $$ = $1; } 29375584Sru | middle_element_list separator element 29475584Sru { $$ = $1; } 29575584Sru ; 29675584Sru 29775584Sruoptional_separator: 29875584Sru /* empty */ 29975584Sru | separator 30075584Sru ; 30175584Sru 30275584Sruseparator: 30375584Sru ';' 30475584Sru | separator ';' 30575584Sru ; 30675584Sru 30775584Sruplaceless_element: 308114402Sru FIGNAME '=' macro_name 309114402Sru { 310114402Sru a_delete graphname; 311114402Sru graphname = new char[strlen($3) + 1]; 312114402Sru strcpy(graphname, $3); 313114402Sru a_delete $3; 314114402Sru } 315114402Sru | 31675584Sru VARIABLE '=' any_expr 31775584Sru { 31875584Sru define_variable($1, $3); 31975584Sru a_delete $1; 32075584Sru } 32175584Sru | VARIABLE ':' '=' any_expr 32275584Sru { 32375584Sru place *p = lookup_label($1); 32475584Sru if (!p) { 32575584Sru lex_error("variable `%1' not defined", $1); 32675584Sru YYABORT; 32775584Sru } 32875584Sru p->obj = 0; 32975584Sru p->x = $4; 33075584Sru p->y = 0.0; 33175584Sru a_delete $1; 33275584Sru } 33375584Sru | UP 33475584Sru { current_direction = UP_DIRECTION; } 33575584Sru | DOWN 33675584Sru { current_direction = DOWN_DIRECTION; } 33775584Sru | LEFT 33875584Sru { current_direction = LEFT_DIRECTION; } 33975584Sru | RIGHT 34075584Sru { current_direction = RIGHT_DIRECTION; } 34175584Sru | COMMAND_LINE 34275584Sru { 34375584Sru olist.append(make_command_object($1.str, $1.filename, 34475584Sru $1.lineno)); 34575584Sru } 34675584Sru | COMMAND print_args 34775584Sru { 34875584Sru olist.append(make_command_object($2.str, $2.filename, 34975584Sru $2.lineno)); 35075584Sru } 35175584Sru | PRINT print_args 35275584Sru { 35375584Sru fprintf(stderr, "%s\n", $2.str); 35475584Sru a_delete $2.str; 355104862Sru fflush(stderr); 35675584Sru } 35775584Sru | SH 35875584Sru { delim_flag = 1; } 35975584Sru DELIMITED 36075584Sru { 36175584Sru delim_flag = 0; 36275584Sru if (safer_flag) 36375584Sru lex_error("unsafe to run command `%1'", $3); 36475584Sru else 36575584Sru system($3); 36675584Sru a_delete $3; 36775584Sru } 36875584Sru | COPY TEXT 36975584Sru { 37075584Sru if (yychar < 0) 37175584Sru do_lookahead(); 37275584Sru do_copy($2.str); 37375584Sru // do not delete the filename 37475584Sru } 37575584Sru | COPY TEXT THRU 37675584Sru { delim_flag = 2; } 37775584Sru DELIMITED 37875584Sru { delim_flag = 0; } 37975584Sru until 38075584Sru { 38175584Sru if (yychar < 0) 38275584Sru do_lookahead(); 38375584Sru copy_file_thru($2.str, $5, $7); 38475584Sru // do not delete the filename 38575584Sru a_delete $5; 38675584Sru a_delete $7; 38775584Sru } 38875584Sru | COPY THRU 38975584Sru { delim_flag = 2; } 39075584Sru DELIMITED 39175584Sru { delim_flag = 0; } 39275584Sru until 39375584Sru { 39475584Sru if (yychar < 0) 39575584Sru do_lookahead(); 39675584Sru copy_rest_thru($4, $6); 39775584Sru a_delete $4; 39875584Sru a_delete $6; 39975584Sru } 40075584Sru | FOR VARIABLE '=' expr TO expr optional_by DO 40175584Sru { delim_flag = 1; } 40275584Sru DELIMITED 40375584Sru { 40475584Sru delim_flag = 0; 40575584Sru if (yychar < 0) 40675584Sru do_lookahead(); 40775584Sru do_for($2, $4, $6, $7.is_multiplicative, $7.val, $10); 40875584Sru } 40975584Sru | simple_if 41075584Sru { 41175584Sru if (yychar < 0) 41275584Sru do_lookahead(); 41375584Sru if ($1.x != 0.0) 41475584Sru push_body($1.body); 41575584Sru a_delete $1.body; 41675584Sru } 41775584Sru | simple_if ELSE 41875584Sru { delim_flag = 1; } 41975584Sru DELIMITED 42075584Sru { 42175584Sru delim_flag = 0; 42275584Sru if (yychar < 0) 42375584Sru do_lookahead(); 42475584Sru if ($1.x != 0.0) 42575584Sru push_body($1.body); 42675584Sru else 42775584Sru push_body($4); 42875584Sru a_delete $1.body; 42975584Sru a_delete $4; 43075584Sru } 43175584Sru | reset_variables 43275584Sru | RESET 43375584Sru { define_variable("scale", 1.0); } 43475584Sru ; 43575584Sru 436114402Srumacro_name: 437114402Sru VARIABLE 438114402Sru | LABEL 439114402Sru ; 440114402Sru 44175584Srureset_variables: 44275584Sru RESET VARIABLE 443104862Sru { 444104862Sru reset($2); 445104862Sru a_delete $2; 446104862Sru } 44775584Sru | reset_variables VARIABLE 448104862Sru { 449104862Sru reset($2); 450104862Sru a_delete $2; 451104862Sru } 45275584Sru | reset_variables ',' VARIABLE 453104862Sru { 454104862Sru reset($3); 455104862Sru a_delete $3; 456104862Sru } 45775584Sru ; 45875584Sru 45975584Sruprint_args: 46075584Sru print_arg 46175584Sru { $$ = $1; } 46275584Sru | print_args print_arg 46375584Sru { 46475584Sru $$.str = new char[strlen($1.str) + strlen($2.str) + 1]; 46575584Sru strcpy($$.str, $1.str); 46675584Sru strcat($$.str, $2.str); 46775584Sru a_delete $1.str; 46875584Sru a_delete $2.str; 46975584Sru if ($1.filename) { 47075584Sru $$.filename = $1.filename; 47175584Sru $$.lineno = $1.lineno; 47275584Sru } 47375584Sru else if ($2.filename) { 47475584Sru $$.filename = $2.filename; 47575584Sru $$.lineno = $2.lineno; 47675584Sru } 47775584Sru } 47875584Sru ; 47975584Sru 48075584Sruprint_arg: 481104862Sru expr %prec ',' 48275584Sru { 48375584Sru $$.str = new char[GDIGITS + 1]; 48475584Sru sprintf($$.str, "%g", $1); 48575584Sru $$.filename = 0; 48675584Sru $$.lineno = 0; 48775584Sru } 48875584Sru | text 48975584Sru { $$ = $1; } 490104862Sru | position %prec ',' 49175584Sru { 49275584Sru $$.str = new char[GDIGITS + 2 + GDIGITS + 1]; 49375584Sru sprintf($$.str, "%g, %g", $1.x, $1.y); 49475584Sru $$.filename = 0; 49575584Sru $$.lineno = 0; 49675584Sru } 497104862Sru ; 49875584Sru 49975584Srusimple_if: 50075584Sru IF any_expr THEN 50175584Sru { delim_flag = 1; } 50275584Sru DELIMITED 503104862Sru { 504104862Sru delim_flag = 0; 505104862Sru $$.x = $2; 506104862Sru $$.body = $5; 507104862Sru } 50875584Sru ; 50975584Sru 51075584Sruuntil: 51175584Sru /* empty */ 51275584Sru { $$ = 0; } 51375584Sru | UNTIL TEXT 51475584Sru { $$ = $2.str; } 51575584Sru ; 51675584Sru 51775584Sruany_expr: 51875584Sru expr 51975584Sru { $$ = $1; } 52075584Sru | text_expr 52175584Sru { $$ = $1; } 52275584Sru ; 52375584Sru 52475584Srutext_expr: 52575584Sru text EQUALEQUAL text 52675584Sru { 52775584Sru $$ = strcmp($1.str, $3.str) == 0; 52875584Sru a_delete $1.str; 52975584Sru a_delete $3.str; 53075584Sru } 53175584Sru | text NOTEQUAL text 53275584Sru { 53375584Sru $$ = strcmp($1.str, $3.str) != 0; 53475584Sru a_delete $1.str; 53575584Sru a_delete $3.str; 53675584Sru } 53775584Sru | text_expr ANDAND text_expr 53875584Sru { $$ = ($1 != 0.0 && $3 != 0.0); } 53975584Sru | text_expr ANDAND expr 54075584Sru { $$ = ($1 != 0.0 && $3 != 0.0); } 54175584Sru | expr ANDAND text_expr 54275584Sru { $$ = ($1 != 0.0 && $3 != 0.0); } 54375584Sru | text_expr OROR text_expr 54475584Sru { $$ = ($1 != 0.0 || $3 != 0.0); } 54575584Sru | text_expr OROR expr 54675584Sru { $$ = ($1 != 0.0 || $3 != 0.0); } 54775584Sru | expr OROR text_expr 54875584Sru { $$ = ($1 != 0.0 || $3 != 0.0); } 54975584Sru | '!' text_expr 55075584Sru { $$ = ($2 == 0.0); } 55175584Sru ; 55275584Sru 55375584Sru 55475584Sruoptional_by: 55575584Sru /* empty */ 556104862Sru { 557104862Sru $$.val = 1.0; 558104862Sru $$.is_multiplicative = 0; 559104862Sru } 56075584Sru | BY expr 561104862Sru { 562104862Sru $$.val = $2; 563104862Sru $$.is_multiplicative = 0; 564104862Sru } 56575584Sru | BY '*' expr 566104862Sru { 567104862Sru $$.val = $3; 568104862Sru $$.is_multiplicative = 1; 569104862Sru } 57075584Sru ; 57175584Sru 57275584Sruelement: 57375584Sru object_spec 57475584Sru { 57575584Sru $$.obj = $1->make_object(¤t_position, 57675584Sru ¤t_direction); 57775584Sru if ($$.obj == 0) 57875584Sru YYABORT; 57975584Sru delete $1; 58075584Sru if ($$.obj) 58175584Sru olist.append($$.obj); 58275584Sru else { 58375584Sru $$.x = current_position.x; 58475584Sru $$.y = current_position.y; 58575584Sru } 58675584Sru } 58775584Sru | LABEL ':' optional_separator element 588104862Sru { 589104862Sru $$ = $4; 590104862Sru define_label($1, & $$); 591104862Sru a_delete $1; 592104862Sru } 59375584Sru | LABEL ':' optional_separator position_not_place 59475584Sru { 59575584Sru $$.obj = 0; 59675584Sru $$.x = $4.x; 59775584Sru $$.y = $4.y; 59875584Sru define_label($1, & $$); 59975584Sru a_delete $1; 60075584Sru } 60175584Sru | LABEL ':' optional_separator place 60275584Sru { 60375584Sru $$ = $4; 60475584Sru define_label($1, & $$); 60575584Sru a_delete $1; 60675584Sru } 60775584Sru | '{' 60875584Sru { 60975584Sru $<state>$.x = current_position.x; 61075584Sru $<state>$.y = current_position.y; 61175584Sru $<state>$.dir = current_direction; 61275584Sru } 61375584Sru element_list '}' 61475584Sru { 61575584Sru current_position.x = $<state>2.x; 61675584Sru current_position.y = $<state>2.y; 61775584Sru current_direction = $<state>2.dir; 61875584Sru } 61975584Sru optional_element 62075584Sru { 62175584Sru $$ = $3; 62275584Sru } 62375584Sru | placeless_element 62475584Sru { 62575584Sru $$.obj = 0; 62675584Sru $$.x = current_position.x; 62775584Sru $$.y = current_position.y; 62875584Sru } 62975584Sru ; 63075584Sru 63175584Sruoptional_element: 63275584Sru /* empty */ 63375584Sru {} 63475584Sru | element 63575584Sru {} 63675584Sru ; 63775584Sru 63875584Sruobject_spec: 63975584Sru BOX 640104862Sru { $$ = new object_spec(BOX_OBJECT); } 64175584Sru | CIRCLE 642104862Sru { $$ = new object_spec(CIRCLE_OBJECT); } 64375584Sru | ELLIPSE 644104862Sru { $$ = new object_spec(ELLIPSE_OBJECT); } 64575584Sru | ARC 64675584Sru { 64775584Sru $$ = new object_spec(ARC_OBJECT); 64875584Sru $$->dir = current_direction; 64975584Sru } 65075584Sru | LINE 65175584Sru { 65275584Sru $$ = new object_spec(LINE_OBJECT); 65375584Sru lookup_variable("lineht", & $$->segment_height); 65475584Sru lookup_variable("linewid", & $$->segment_width); 65575584Sru $$->dir = current_direction; 65675584Sru } 65775584Sru | ARROW 65875584Sru { 65975584Sru $$ = new object_spec(ARROW_OBJECT); 66075584Sru lookup_variable("lineht", & $$->segment_height); 66175584Sru lookup_variable("linewid", & $$->segment_width); 66275584Sru $$->dir = current_direction; 66375584Sru } 66475584Sru | MOVE 66575584Sru { 66675584Sru $$ = new object_spec(MOVE_OBJECT); 66775584Sru lookup_variable("moveht", & $$->segment_height); 66875584Sru lookup_variable("movewid", & $$->segment_width); 66975584Sru $$->dir = current_direction; 67075584Sru } 67175584Sru | SPLINE 67275584Sru { 67375584Sru $$ = new object_spec(SPLINE_OBJECT); 67475584Sru lookup_variable("lineht", & $$->segment_height); 67575584Sru lookup_variable("linewid", & $$->segment_width); 67675584Sru $$->dir = current_direction; 67775584Sru } 678104862Sru | text %prec TEXT 67975584Sru { 68075584Sru $$ = new object_spec(TEXT_OBJECT); 68175584Sru $$->text = new text_item($1.str, $1.filename, $1.lineno); 68275584Sru } 68375584Sru | PLOT expr 68475584Sru { 68575584Sru $$ = new object_spec(TEXT_OBJECT); 68675584Sru $$->text = new text_item(format_number(0, $2), 0, -1); 68775584Sru } 68875584Sru | PLOT expr text 68975584Sru { 69075584Sru $$ = new object_spec(TEXT_OBJECT); 69175584Sru $$->text = new text_item(format_number($3.str, $2), 69275584Sru $3.filename, $3.lineno); 69375584Sru a_delete $3.str; 69475584Sru } 69575584Sru | '[' 69675584Sru { 69775584Sru saved_state *p = new saved_state; 69875584Sru $<pstate>$ = p; 69975584Sru p->x = current_position.x; 70075584Sru p->y = current_position.y; 70175584Sru p->dir = current_direction; 70275584Sru p->tbl = current_table; 70375584Sru p->prev = current_saved_state; 70475584Sru current_position.x = 0.0; 70575584Sru current_position.y = 0.0; 70675584Sru current_table = new PTABLE(place); 70775584Sru current_saved_state = p; 70875584Sru olist.append(make_mark_object()); 70975584Sru } 71075584Sru element_list ']' 71175584Sru { 71275584Sru current_position.x = $<pstate>2->x; 71375584Sru current_position.y = $<pstate>2->y; 71475584Sru current_direction = $<pstate>2->dir; 71575584Sru $$ = new object_spec(BLOCK_OBJECT); 71675584Sru olist.wrap_up_block(& $$->oblist); 71775584Sru $$->tbl = current_table; 71875584Sru current_table = $<pstate>2->tbl; 71975584Sru current_saved_state = $<pstate>2->prev; 72075584Sru delete $<pstate>2; 72175584Sru } 72275584Sru | object_spec HEIGHT expr 72375584Sru { 72475584Sru $$ = $1; 72575584Sru $$->height = $3; 72675584Sru $$->flags |= HAS_HEIGHT; 72775584Sru } 72875584Sru | object_spec RADIUS expr 72975584Sru { 73075584Sru $$ = $1; 73175584Sru $$->radius = $3; 73275584Sru $$->flags |= HAS_RADIUS; 73375584Sru } 73475584Sru | object_spec WIDTH expr 73575584Sru { 73675584Sru $$ = $1; 73775584Sru $$->width = $3; 73875584Sru $$->flags |= HAS_WIDTH; 73975584Sru } 74075584Sru | object_spec DIAMETER expr 74175584Sru { 74275584Sru $$ = $1; 74375584Sru $$->radius = $3/2.0; 74475584Sru $$->flags |= HAS_RADIUS; 74575584Sru } 746104862Sru | object_spec expr %prec HEIGHT 74775584Sru { 74875584Sru $$ = $1; 74975584Sru $$->flags |= HAS_SEGMENT; 75075584Sru switch ($$->dir) { 75175584Sru case UP_DIRECTION: 75275584Sru $$->segment_pos.y += $2; 75375584Sru break; 75475584Sru case DOWN_DIRECTION: 75575584Sru $$->segment_pos.y -= $2; 75675584Sru break; 75775584Sru case RIGHT_DIRECTION: 75875584Sru $$->segment_pos.x += $2; 75975584Sru break; 76075584Sru case LEFT_DIRECTION: 76175584Sru $$->segment_pos.x -= $2; 76275584Sru break; 76375584Sru } 76475584Sru } 76575584Sru | object_spec UP 76675584Sru { 76775584Sru $$ = $1; 76875584Sru $$->dir = UP_DIRECTION; 76975584Sru $$->flags |= HAS_SEGMENT; 77075584Sru $$->segment_pos.y += $$->segment_height; 77175584Sru } 77275584Sru | object_spec UP expr 77375584Sru { 77475584Sru $$ = $1; 77575584Sru $$->dir = UP_DIRECTION; 77675584Sru $$->flags |= HAS_SEGMENT; 77775584Sru $$->segment_pos.y += $3; 77875584Sru } 77975584Sru | object_spec DOWN 78075584Sru { 78175584Sru $$ = $1; 78275584Sru $$->dir = DOWN_DIRECTION; 78375584Sru $$->flags |= HAS_SEGMENT; 78475584Sru $$->segment_pos.y -= $$->segment_height; 78575584Sru } 78675584Sru | object_spec DOWN expr 78775584Sru { 78875584Sru $$ = $1; 78975584Sru $$->dir = DOWN_DIRECTION; 79075584Sru $$->flags |= HAS_SEGMENT; 79175584Sru $$->segment_pos.y -= $3; 79275584Sru } 79375584Sru | object_spec RIGHT 79475584Sru { 79575584Sru $$ = $1; 79675584Sru $$->dir = RIGHT_DIRECTION; 79775584Sru $$->flags |= HAS_SEGMENT; 79875584Sru $$->segment_pos.x += $$->segment_width; 79975584Sru } 80075584Sru | object_spec RIGHT expr 80175584Sru { 80275584Sru $$ = $1; 80375584Sru $$->dir = RIGHT_DIRECTION; 80475584Sru $$->flags |= HAS_SEGMENT; 80575584Sru $$->segment_pos.x += $3; 80675584Sru } 80775584Sru | object_spec LEFT 80875584Sru { 80975584Sru $$ = $1; 81075584Sru $$->dir = LEFT_DIRECTION; 81175584Sru $$->flags |= HAS_SEGMENT; 81275584Sru $$->segment_pos.x -= $$->segment_width; 81375584Sru } 81475584Sru | object_spec LEFT expr 81575584Sru { 81675584Sru $$ = $1; 81775584Sru $$->dir = LEFT_DIRECTION; 81875584Sru $$->flags |= HAS_SEGMENT; 81975584Sru $$->segment_pos.x -= $3; 82075584Sru } 82175584Sru | object_spec FROM position 82275584Sru { 82375584Sru $$ = $1; 82475584Sru $$->flags |= HAS_FROM; 82575584Sru $$->from.x = $3.x; 82675584Sru $$->from.y = $3.y; 82775584Sru } 82875584Sru | object_spec TO position 82975584Sru { 83075584Sru $$ = $1; 83175584Sru if ($$->flags & HAS_SEGMENT) 83275584Sru $$->segment_list = new segment($$->segment_pos, 83375584Sru $$->segment_is_absolute, 83475584Sru $$->segment_list); 83575584Sru $$->flags |= HAS_SEGMENT; 83675584Sru $$->segment_pos.x = $3.x; 83775584Sru $$->segment_pos.y = $3.y; 83875584Sru $$->segment_is_absolute = 1; 83975584Sru $$->flags |= HAS_TO; 84075584Sru $$->to.x = $3.x; 84175584Sru $$->to.y = $3.y; 84275584Sru } 84375584Sru | object_spec AT position 84475584Sru { 84575584Sru $$ = $1; 84675584Sru $$->flags |= HAS_AT; 84775584Sru $$->at.x = $3.x; 84875584Sru $$->at.y = $3.y; 84975584Sru if ($$->type != ARC_OBJECT) { 85075584Sru $$->flags |= HAS_FROM; 85175584Sru $$->from.x = $3.x; 85275584Sru $$->from.y = $3.y; 85375584Sru } 85475584Sru } 85575584Sru | object_spec WITH path 85675584Sru { 85775584Sru $$ = $1; 85875584Sru $$->flags |= HAS_WITH; 85975584Sru $$->with = $3; 86075584Sru } 861104862Sru | object_spec WITH position %prec ',' 862104862Sru { 863104862Sru $$ = $1; 864104862Sru $$->flags |= HAS_WITH; 865104862Sru position pos; 866104862Sru pos.x = $3.x; 867104862Sru pos.y = $3.y; 868104862Sru $$->with = new path(pos); 869104862Sru } 87075584Sru | object_spec BY expr_pair 87175584Sru { 87275584Sru $$ = $1; 87375584Sru $$->flags |= HAS_SEGMENT; 87475584Sru $$->segment_pos.x += $3.x; 87575584Sru $$->segment_pos.y += $3.y; 87675584Sru } 87775584Sru | object_spec THEN 87875584Sru { 87975584Sru $$ = $1; 88075584Sru if ($$->flags & HAS_SEGMENT) { 88175584Sru $$->segment_list = new segment($$->segment_pos, 88275584Sru $$->segment_is_absolute, 88375584Sru $$->segment_list); 88475584Sru $$->flags &= ~HAS_SEGMENT; 88575584Sru $$->segment_pos.x = $$->segment_pos.y = 0.0; 88675584Sru $$->segment_is_absolute = 0; 88775584Sru } 88875584Sru } 88975584Sru | object_spec SOLID 89075584Sru { 89175584Sru $$ = $1; // nothing 89275584Sru } 89375584Sru | object_spec DOTTED 89475584Sru { 89575584Sru $$ = $1; 89675584Sru $$->flags |= IS_DOTTED; 89775584Sru lookup_variable("dashwid", & $$->dash_width); 89875584Sru } 89975584Sru | object_spec DOTTED expr 90075584Sru { 90175584Sru $$ = $1; 90275584Sru $$->flags |= IS_DOTTED; 90375584Sru $$->dash_width = $3; 90475584Sru } 90575584Sru | object_spec DASHED 90675584Sru { 90775584Sru $$ = $1; 90875584Sru $$->flags |= IS_DASHED; 90975584Sru lookup_variable("dashwid", & $$->dash_width); 91075584Sru } 91175584Sru | object_spec DASHED expr 91275584Sru { 91375584Sru $$ = $1; 91475584Sru $$->flags |= IS_DASHED; 91575584Sru $$->dash_width = $3; 91675584Sru } 91775584Sru | object_spec FILL 91875584Sru { 91975584Sru $$ = $1; 92075584Sru $$->flags |= IS_DEFAULT_FILLED; 92175584Sru } 92275584Sru | object_spec FILL expr 92375584Sru { 92475584Sru $$ = $1; 92575584Sru $$->flags |= IS_FILLED; 92675584Sru $$->fill = $3; 92775584Sru } 928104862Sru | object_spec SHADED text 929104862Sru { 930104862Sru $$ = $1; 931104862Sru $$->flags |= (IS_SHADED | IS_FILLED); 932104862Sru $$->shaded = new char[strlen($3.str)+1]; 933104862Sru strcpy($$->shaded, $3.str); 934104862Sru } 935104862Sru | object_spec COLORED text 936104862Sru { 937104862Sru $$ = $1; 938104862Sru $$->flags |= (IS_SHADED | IS_OUTLINED | IS_FILLED); 939104862Sru $$->shaded = new char[strlen($3.str)+1]; 940104862Sru strcpy($$->shaded, $3.str); 941104862Sru $$->outlined = new char[strlen($3.str)+1]; 942104862Sru strcpy($$->outlined, $3.str); 943104862Sru } 944104862Sru | object_spec OUTLINED text 945104862Sru { 946104862Sru $$ = $1; 947104862Sru $$->flags |= IS_OUTLINED; 948104862Sru $$->outlined = new char[strlen($3.str)+1]; 949104862Sru strcpy($$->outlined, $3.str); 950104862Sru } 95175584Sru | object_spec CHOP 95275584Sru { 95375584Sru $$ = $1; 95475584Sru // line chop chop means line chop 0 chop 0 95575584Sru if ($$->flags & IS_DEFAULT_CHOPPED) { 95675584Sru $$->flags |= IS_CHOPPED; 95775584Sru $$->flags &= ~IS_DEFAULT_CHOPPED; 95875584Sru $$->start_chop = $$->end_chop = 0.0; 95975584Sru } 96075584Sru else if ($$->flags & IS_CHOPPED) { 96175584Sru $$->end_chop = 0.0; 96275584Sru } 96375584Sru else { 96475584Sru $$->flags |= IS_DEFAULT_CHOPPED; 96575584Sru } 96675584Sru } 96775584Sru | object_spec CHOP expr 96875584Sru { 96975584Sru $$ = $1; 97075584Sru if ($$->flags & IS_DEFAULT_CHOPPED) { 97175584Sru $$->flags |= IS_CHOPPED; 97275584Sru $$->flags &= ~IS_DEFAULT_CHOPPED; 97375584Sru $$->start_chop = 0.0; 97475584Sru $$->end_chop = $3; 97575584Sru } 97675584Sru else if ($$->flags & IS_CHOPPED) { 97775584Sru $$->end_chop = $3; 97875584Sru } 97975584Sru else { 98075584Sru $$->start_chop = $$->end_chop = $3; 98175584Sru $$->flags |= IS_CHOPPED; 98275584Sru } 98375584Sru } 98475584Sru | object_spec SAME 98575584Sru { 98675584Sru $$ = $1; 98775584Sru $$->flags |= IS_SAME; 98875584Sru } 98975584Sru | object_spec INVISIBLE 99075584Sru { 99175584Sru $$ = $1; 99275584Sru $$->flags |= IS_INVISIBLE; 99375584Sru } 99475584Sru | object_spec LEFT_ARROW_HEAD 99575584Sru { 99675584Sru $$ = $1; 99775584Sru $$->flags |= HAS_LEFT_ARROW_HEAD; 99875584Sru } 99975584Sru | object_spec RIGHT_ARROW_HEAD 100075584Sru { 100175584Sru $$ = $1; 100275584Sru $$->flags |= HAS_RIGHT_ARROW_HEAD; 100375584Sru } 100475584Sru | object_spec DOUBLE_ARROW_HEAD 100575584Sru { 100675584Sru $$ = $1; 100775584Sru $$->flags |= (HAS_LEFT_ARROW_HEAD|HAS_RIGHT_ARROW_HEAD); 100875584Sru } 100975584Sru | object_spec CW 101075584Sru { 101175584Sru $$ = $1; 101275584Sru $$->flags |= IS_CLOCKWISE; 101375584Sru } 101475584Sru | object_spec CCW 101575584Sru { 101675584Sru $$ = $1; 101775584Sru $$->flags &= ~IS_CLOCKWISE; 101875584Sru } 1019104862Sru | object_spec text %prec TEXT 102075584Sru { 102175584Sru $$ = $1; 102275584Sru text_item **p; 102375584Sru for (p = & $$->text; *p; p = &(*p)->next) 102475584Sru ; 102575584Sru *p = new text_item($2.str, $2.filename, $2.lineno); 102675584Sru } 102775584Sru | object_spec LJUST 102875584Sru { 102975584Sru $$ = $1; 103075584Sru if ($$->text) { 103175584Sru text_item *p; 103275584Sru for (p = $$->text; p->next; p = p->next) 103375584Sru ; 103475584Sru p->adj.h = LEFT_ADJUST; 103575584Sru } 103675584Sru } 103775584Sru | object_spec RJUST 103875584Sru { 103975584Sru $$ = $1; 104075584Sru if ($$->text) { 104175584Sru text_item *p; 104275584Sru for (p = $$->text; p->next; p = p->next) 104375584Sru ; 104475584Sru p->adj.h = RIGHT_ADJUST; 104575584Sru } 104675584Sru } 104775584Sru | object_spec ABOVE 104875584Sru { 104975584Sru $$ = $1; 105075584Sru if ($$->text) { 105175584Sru text_item *p; 105275584Sru for (p = $$->text; p->next; p = p->next) 105375584Sru ; 105475584Sru p->adj.v = ABOVE_ADJUST; 105575584Sru } 105675584Sru } 105775584Sru | object_spec BELOW 105875584Sru { 105975584Sru $$ = $1; 106075584Sru if ($$->text) { 106175584Sru text_item *p; 106275584Sru for (p = $$->text; p->next; p = p->next) 106375584Sru ; 106475584Sru p->adj.v = BELOW_ADJUST; 106575584Sru } 106675584Sru } 106775584Sru | object_spec THICKNESS expr 106875584Sru { 106975584Sru $$ = $1; 107075584Sru $$->flags |= HAS_THICKNESS; 107175584Sru $$->thickness = $3; 107275584Sru } 107375584Sru | object_spec ALIGNED 107475584Sru { 107575584Sru $$ = $1; 107675584Sru $$->flags |= IS_ALIGNED; 107775584Sru } 107875584Sru ; 107975584Sru 108075584Srutext: 108175584Sru TEXT 1082104862Sru { $$ = $1; } 108375584Sru | SPRINTF '(' TEXT sprintf_args ')' 108475584Sru { 108575584Sru $$.filename = $3.filename; 108675584Sru $$.lineno = $3.lineno; 108775584Sru $$.str = do_sprintf($3.str, $4.v, $4.nv); 108875584Sru a_delete $4.v; 108975584Sru a_delete $3.str; 109075584Sru } 109175584Sru ; 109275584Sru 109375584Srusprintf_args: 109475584Sru /* empty */ 109575584Sru { 109675584Sru $$.v = 0; 109775584Sru $$.nv = 0; 109875584Sru $$.maxv = 0; 109975584Sru } 110075584Sru | sprintf_args ',' expr 110175584Sru { 110275584Sru $$ = $1; 110375584Sru if ($$.nv >= $$.maxv) { 110475584Sru if ($$.nv == 0) { 110575584Sru $$.v = new double[4]; 110675584Sru $$.maxv = 4; 110775584Sru } 110875584Sru else { 110975584Sru double *oldv = $$.v; 111075584Sru $$.maxv *= 2; 1111151497Sru#if 0 111275584Sru $$.v = new double[$$.maxv]; 111375584Sru memcpy($$.v, oldv, $$.nv*sizeof(double)); 1114151497Sru#else 1115151497Sru // workaround for bug in Compaq C++ V6.5-033 1116151497Sru // for Compaq Tru64 UNIX V5.1A (Rev. 1885) 1117151497Sru double *foo = new double[$$.maxv]; 1118151497Sru memcpy(foo, oldv, $$.nv*sizeof(double)); 1119151497Sru $$.v = foo; 1120151497Sru#endif 112175584Sru a_delete oldv; 112275584Sru } 112375584Sru } 112475584Sru $$.v[$$.nv] = $3; 112575584Sru $$.nv += 1; 112675584Sru } 112775584Sru ; 112875584Sru 112975584Sruposition: 113075584Sru position_not_place 113175584Sru { $$ = $1; } 113275584Sru | place 113375584Sru { 113475584Sru position pos = $1; 113575584Sru $$.x = pos.x; 113675584Sru $$.y = pos.y; 113775584Sru } 1138151497Sru | '(' place ')' 1139151497Sru { 1140151497Sru position pos = $2; 1141151497Sru $$.x = pos.x; 1142151497Sru $$.y = pos.y; 1143151497Sru } 114475584Sru ; 114575584Sru 114675584Sruposition_not_place: 114775584Sru expr_pair 114875584Sru { $$ = $1; } 114975584Sru | position '+' expr_pair 115075584Sru { 115175584Sru $$.x = $1.x + $3.x; 115275584Sru $$.y = $1.y + $3.y; 115375584Sru } 1154151497Sru | '(' position '+' expr_pair ')' 1155151497Sru { 1156151497Sru $$.x = $2.x + $4.x; 1157151497Sru $$.y = $2.y + $4.y; 1158151497Sru } 115975584Sru | position '-' expr_pair 116075584Sru { 116175584Sru $$.x = $1.x - $3.x; 116275584Sru $$.y = $1.y - $3.y; 116375584Sru } 1164151497Sru | '(' position '-' expr_pair ')' 1165151497Sru { 1166151497Sru $$.x = $2.x - $4.x; 1167151497Sru $$.y = $2.y - $4.y; 1168151497Sru } 116975584Sru | '(' position ',' position ')' 117075584Sru { 117175584Sru $$.x = $2.x; 117275584Sru $$.y = $4.y; 117375584Sru } 117475584Sru | expr between position AND position 117575584Sru { 117675584Sru $$.x = (1.0 - $1)*$3.x + $1*$5.x; 117775584Sru $$.y = (1.0 - $1)*$3.y + $1*$5.y; 117875584Sru } 1179151497Sru | '(' expr between position AND position ')' 1180151497Sru { 1181151497Sru $$.x = (1.0 - $2)*$4.x + $2*$6.x; 1182151497Sru $$.y = (1.0 - $2)*$4.y + $2*$6.y; 1183151497Sru } 118475584Sru | expr '<' position ',' position '>' 118575584Sru { 118675584Sru $$.x = (1.0 - $1)*$3.x + $1*$5.x; 118775584Sru $$.y = (1.0 - $1)*$3.y + $1*$5.y; 118875584Sru } 1189151497Sru | '(' expr '<' position ',' position '>' ')' 1190151497Sru { 1191151497Sru $$.x = (1.0 - $2)*$4.x + $2*$6.x; 1192151497Sru $$.y = (1.0 - $2)*$4.y + $2*$6.y; 1193151497Sru } 119475584Sru ; 119575584Sru 119675584Srubetween: 119775584Sru BETWEEN 119875584Sru | OF THE WAY BETWEEN 119975584Sru ; 120075584Sru 120175584Sruexpr_pair: 120275584Sru expr ',' expr 1203104862Sru { 1204104862Sru $$.x = $1; 1205104862Sru $$.y = $3; 1206104862Sru } 120775584Sru | '(' expr_pair ')' 120875584Sru { $$ = $2; } 120975584Sru ; 121075584Sru 121175584Sruplace: 1212104862Sru /* line at A left == line (at A) left */ 1213104862Sru label %prec CHOP 121475584Sru { $$ = $1; } 121575584Sru | label corner 121675584Sru { 121775584Sru path pth($2); 121875584Sru if (!pth.follow($1, & $$)) 121975584Sru YYABORT; 122075584Sru } 122175584Sru | corner label 122275584Sru { 122375584Sru path pth($1); 122475584Sru if (!pth.follow($2, & $$)) 122575584Sru YYABORT; 122675584Sru } 122775584Sru | corner OF label 122875584Sru { 122975584Sru path pth($1); 123075584Sru if (!pth.follow($3, & $$)) 123175584Sru YYABORT; 123275584Sru } 123375584Sru | HERE 123475584Sru { 123575584Sru $$.x = current_position.x; 123675584Sru $$.y = current_position.y; 123775584Sru $$.obj = 0; 123875584Sru } 123975584Sru ; 124075584Sru 124175584Srulabel: 124275584Sru LABEL 124375584Sru { 124475584Sru place *p = lookup_label($1); 124575584Sru if (!p) { 124675584Sru lex_error("there is no place `%1'", $1); 124775584Sru YYABORT; 124875584Sru } 124975584Sru $$ = *p; 125075584Sru a_delete $1; 125175584Sru } 125275584Sru | nth_primitive 1253104862Sru { $$.obj = $1; } 125475584Sru | label '.' LABEL 125575584Sru { 125675584Sru path pth($3); 125775584Sru if (!pth.follow($1, & $$)) 125875584Sru YYABORT; 125975584Sru } 126075584Sru ; 126175584Sru 126275584Sruordinal: 126375584Sru ORDINAL 126475584Sru { $$ = $1; } 126575584Sru | '`' any_expr TH 126675584Sru { 126775584Sru // XXX Check for overflow (and non-integers?). 126875584Sru $$ = (int)$2; 126975584Sru } 127075584Sru ; 127175584Sru 127275584Sruoptional_ordinal_last: 1273104862Sru LAST 127475584Sru { $$ = 1; } 127575584Sru | ordinal LAST 127675584Sru { $$ = $1; } 127775584Sru ; 127875584Sru 127975584Srunth_primitive: 128075584Sru ordinal object_type 128175584Sru { 128275584Sru int count = 0; 128375584Sru object *p; 128475584Sru for (p = olist.head; p != 0; p = p->next) 128575584Sru if (p->type() == $2 && ++count == $1) { 128675584Sru $$ = p; 128775584Sru break; 128875584Sru } 128975584Sru if (p == 0) { 129075584Sru lex_error("there is no %1%2 %3", $1, ordinal_postfix($1), 129175584Sru object_type_name($2)); 129275584Sru YYABORT; 129375584Sru } 129475584Sru } 129575584Sru | optional_ordinal_last object_type 129675584Sru { 129775584Sru int count = 0; 129875584Sru object *p; 129975584Sru for (p = olist.tail; p != 0; p = p->prev) 130075584Sru if (p->type() == $2 && ++count == $1) { 130175584Sru $$ = p; 130275584Sru break; 130375584Sru } 130475584Sru if (p == 0) { 130575584Sru lex_error("there is no %1%2 last %3", $1, 130675584Sru ordinal_postfix($1), object_type_name($2)); 130775584Sru YYABORT; 130875584Sru } 130975584Sru } 131075584Sru ; 131175584Sru 131275584Sruobject_type: 131375584Sru BOX 131475584Sru { $$ = BOX_OBJECT; } 131575584Sru | CIRCLE 131675584Sru { $$ = CIRCLE_OBJECT; } 131775584Sru | ELLIPSE 131875584Sru { $$ = ELLIPSE_OBJECT; } 131975584Sru | ARC 132075584Sru { $$ = ARC_OBJECT; } 132175584Sru | LINE 132275584Sru { $$ = LINE_OBJECT; } 132375584Sru | ARROW 132475584Sru { $$ = ARROW_OBJECT; } 132575584Sru | SPLINE 132675584Sru { $$ = SPLINE_OBJECT; } 132775584Sru | '[' ']' 132875584Sru { $$ = BLOCK_OBJECT; } 132975584Sru | TEXT 133075584Sru { $$ = TEXT_OBJECT; } 133175584Sru ; 133275584Sru 133375584Srulabel_path: 133475584Sru '.' LABEL 1335104862Sru { $$ = new path($2); } 133675584Sru | label_path '.' LABEL 133775584Sru { 133875584Sru $$ = $1; 133975584Sru $$->append($3); 134075584Sru } 134175584Sru ; 134275584Sru 134375584Srurelative_path: 1344104862Sru corner %prec CHOP 1345104862Sru { $$ = new path($1); } 134675584Sru /* give this a lower precedence than LEFT and RIGHT so that 134775584Sru [A: box] with .A left == [A: box] with (.A left) */ 1348104862Sru | label_path %prec TEXT 1349104862Sru { $$ = $1; } 135075584Sru | label_path corner 135175584Sru { 135275584Sru $$ = $1; 135375584Sru $$->append($2); 135475584Sru } 135575584Sru ; 135675584Sru 135775584Srupath: 135875584Sru relative_path 1359104862Sru { $$ = $1; } 136075584Sru | '(' relative_path ',' relative_path ')' 136175584Sru { 136275584Sru $$ = $2; 136375584Sru $$->set_ypath($4); 136475584Sru } 136575584Sru /* The rest of these rules are a compatibility sop. */ 136675584Sru | ORDINAL LAST object_type relative_path 136775584Sru { 136875584Sru lex_warning("`%1%2 last %3' in `with' argument ignored", 136975584Sru $1, ordinal_postfix($1), object_type_name($3)); 137075584Sru $$ = $4; 137175584Sru } 137275584Sru | LAST object_type relative_path 137375584Sru { 137475584Sru lex_warning("`last %1' in `with' argument ignored", 137575584Sru object_type_name($2)); 137675584Sru $$ = $3; 137775584Sru } 137875584Sru | ORDINAL object_type relative_path 137975584Sru { 138075584Sru lex_warning("`%1%2 %3' in `with' argument ignored", 138175584Sru $1, ordinal_postfix($1), object_type_name($2)); 138275584Sru $$ = $3; 138375584Sru } 138475584Sru | LABEL relative_path 138575584Sru { 138675584Sru lex_warning("initial `%1' in `with' argument ignored", $1); 138775584Sru a_delete $1; 138875584Sru $$ = $2; 138975584Sru } 139075584Sru ; 139175584Sru 139275584Srucorner: 139375584Sru DOT_N 139475584Sru { $$ = &object::north; } 139575584Sru | DOT_E 139675584Sru { $$ = &object::east; } 139775584Sru | DOT_W 139875584Sru { $$ = &object::west; } 139975584Sru | DOT_S 140075584Sru { $$ = &object::south; } 140175584Sru | DOT_NE 140275584Sru { $$ = &object::north_east; } 140375584Sru | DOT_SE 140475584Sru { $$ = &object:: south_east; } 140575584Sru | DOT_NW 140675584Sru { $$ = &object::north_west; } 140775584Sru | DOT_SW 140875584Sru { $$ = &object::south_west; } 140975584Sru | DOT_C 141075584Sru { $$ = &object::center; } 141175584Sru | DOT_START 141275584Sru { $$ = &object::start; } 141375584Sru | DOT_END 141475584Sru { $$ = &object::end; } 141575584Sru | TOP 141675584Sru { $$ = &object::north; } 141775584Sru | BOTTOM 141875584Sru { $$ = &object::south; } 141975584Sru | LEFT 142075584Sru { $$ = &object::west; } 142175584Sru | RIGHT 142275584Sru { $$ = &object::east; } 142375584Sru | UPPER LEFT 142475584Sru { $$ = &object::north_west; } 142575584Sru | LOWER LEFT 142675584Sru { $$ = &object::south_west; } 142775584Sru | UPPER RIGHT 142875584Sru { $$ = &object::north_east; } 142975584Sru | LOWER RIGHT 143075584Sru { $$ = &object::south_east; } 143175584Sru | LEFT_CORNER 143275584Sru { $$ = &object::west; } 143375584Sru | RIGHT_CORNER 143475584Sru { $$ = &object::east; } 143575584Sru | UPPER LEFT_CORNER 143675584Sru { $$ = &object::north_west; } 143775584Sru | LOWER LEFT_CORNER 143875584Sru { $$ = &object::south_west; } 143975584Sru | UPPER RIGHT_CORNER 144075584Sru { $$ = &object::north_east; } 144175584Sru | LOWER RIGHT_CORNER 144275584Sru { $$ = &object::south_east; } 1443104862Sru | NORTH 1444104862Sru { $$ = &object::north; } 1445104862Sru | SOUTH 1446104862Sru { $$ = &object::south; } 1447104862Sru | EAST 1448104862Sru { $$ = &object::east; } 1449104862Sru | WEST 1450104862Sru { $$ = &object::west; } 145175584Sru | CENTER 145275584Sru { $$ = &object::center; } 145375584Sru | START 145475584Sru { $$ = &object::start; } 145575584Sru | END 145675584Sru { $$ = &object::end; } 145775584Sru ; 145875584Sru 145975584Sruexpr: 146075584Sru VARIABLE 146175584Sru { 146275584Sru if (!lookup_variable($1, & $$)) { 146375584Sru lex_error("there is no variable `%1'", $1); 146475584Sru YYABORT; 146575584Sru } 146675584Sru a_delete $1; 146775584Sru } 146875584Sru | NUMBER 146975584Sru { $$ = $1; } 147075584Sru | place DOT_X 147175584Sru { 147275584Sru if ($1.obj != 0) 147375584Sru $$ = $1.obj->origin().x; 147475584Sru else 147575584Sru $$ = $1.x; 147675584Sru } 147775584Sru | place DOT_Y 147875584Sru { 147975584Sru if ($1.obj != 0) 148075584Sru $$ = $1.obj->origin().y; 148175584Sru else 148275584Sru $$ = $1.y; 148375584Sru } 148475584Sru | place DOT_HT 148575584Sru { 148675584Sru if ($1.obj != 0) 148775584Sru $$ = $1.obj->height(); 148875584Sru else 148975584Sru $$ = 0.0; 149075584Sru } 149175584Sru | place DOT_WID 149275584Sru { 149375584Sru if ($1.obj != 0) 149475584Sru $$ = $1.obj->width(); 149575584Sru else 149675584Sru $$ = 0.0; 149775584Sru } 149875584Sru | place DOT_RAD 149975584Sru { 150075584Sru if ($1.obj != 0) 150175584Sru $$ = $1.obj->radius(); 150275584Sru else 150375584Sru $$ = 0.0; 150475584Sru } 150575584Sru | expr '+' expr 150675584Sru { $$ = $1 + $3; } 150775584Sru | expr '-' expr 150875584Sru { $$ = $1 - $3; } 150975584Sru | expr '*' expr 151075584Sru { $$ = $1 * $3; } 151175584Sru | expr '/' expr 151275584Sru { 151375584Sru if ($3 == 0.0) { 151475584Sru lex_error("division by zero"); 151575584Sru YYABORT; 151675584Sru } 151775584Sru $$ = $1/$3; 151875584Sru } 151975584Sru | expr '%' expr 152075584Sru { 152175584Sru if ($3 == 0.0) { 152275584Sru lex_error("modulus by zero"); 152375584Sru YYABORT; 152475584Sru } 152575584Sru $$ = fmod($1, $3); 152675584Sru } 152775584Sru | expr '^' expr 152875584Sru { 152975584Sru errno = 0; 153075584Sru $$ = pow($1, $3); 153175584Sru if (errno == EDOM) { 153275584Sru lex_error("arguments to `^' operator out of domain"); 153375584Sru YYABORT; 153475584Sru } 153575584Sru if (errno == ERANGE) { 153675584Sru lex_error("result of `^' operator out of range"); 153775584Sru YYABORT; 153875584Sru } 153975584Sru } 1540104862Sru | '-' expr %prec '!' 154175584Sru { $$ = -$2; } 154275584Sru | '(' any_expr ')' 154375584Sru { $$ = $2; } 154475584Sru | SIN '(' any_expr ')' 154575584Sru { 154675584Sru errno = 0; 154775584Sru $$ = sin($3); 154875584Sru if (errno == ERANGE) { 154975584Sru lex_error("sin result out of range"); 155075584Sru YYABORT; 155175584Sru } 155275584Sru } 155375584Sru | COS '(' any_expr ')' 155475584Sru { 155575584Sru errno = 0; 155675584Sru $$ = cos($3); 155775584Sru if (errno == ERANGE) { 155875584Sru lex_error("cos result out of range"); 155975584Sru YYABORT; 156075584Sru } 156175584Sru } 156275584Sru | ATAN2 '(' any_expr ',' any_expr ')' 156375584Sru { 156475584Sru errno = 0; 156575584Sru $$ = atan2($3, $5); 156675584Sru if (errno == EDOM) { 156775584Sru lex_error("atan2 argument out of domain"); 156875584Sru YYABORT; 156975584Sru } 157075584Sru if (errno == ERANGE) { 157175584Sru lex_error("atan2 result out of range"); 157275584Sru YYABORT; 157375584Sru } 157475584Sru } 157575584Sru | LOG '(' any_expr ')' 157675584Sru { 157775584Sru errno = 0; 157875584Sru $$ = log10($3); 157975584Sru if (errno == ERANGE) { 158075584Sru lex_error("log result out of range"); 158175584Sru YYABORT; 158275584Sru } 158375584Sru } 158475584Sru | EXP '(' any_expr ')' 158575584Sru { 158675584Sru errno = 0; 158775584Sru $$ = pow(10.0, $3); 158875584Sru if (errno == ERANGE) { 158975584Sru lex_error("exp result out of range"); 159075584Sru YYABORT; 159175584Sru } 159275584Sru } 159375584Sru | SQRT '(' any_expr ')' 159475584Sru { 159575584Sru errno = 0; 159675584Sru $$ = sqrt($3); 159775584Sru if (errno == EDOM) { 159875584Sru lex_error("sqrt argument out of domain"); 159975584Sru YYABORT; 160075584Sru } 160175584Sru } 160275584Sru | K_MAX '(' any_expr ',' any_expr ')' 160375584Sru { $$ = $3 > $5 ? $3 : $5; } 160475584Sru | K_MIN '(' any_expr ',' any_expr ')' 160575584Sru { $$ = $3 < $5 ? $3 : $5; } 160675584Sru | INT '(' any_expr ')' 160775584Sru { $$ = floor($3); } 160875584Sru | RAND '(' any_expr ')' 160975584Sru { $$ = 1.0 + floor(((rand()&0x7fff)/double(0x7fff))*$3); } 161075584Sru | RAND '(' ')' 161175584Sru { 161275584Sru /* return a random number in the range [0,1) */ 161375584Sru /* portable, but not very random */ 161475584Sru $$ = (rand() & 0x7fff) / double(0x8000); 161575584Sru } 161675584Sru | SRAND '(' any_expr ')' 1617104862Sru { 1618104862Sru $$ = 0; 1619104862Sru srand((unsigned int)$3); 1620104862Sru } 162175584Sru | expr '<' expr 162275584Sru { $$ = ($1 < $3); } 162375584Sru | expr LESSEQUAL expr 162475584Sru { $$ = ($1 <= $3); } 162575584Sru | expr '>' expr 162675584Sru { $$ = ($1 > $3); } 162775584Sru | expr GREATEREQUAL expr 162875584Sru { $$ = ($1 >= $3); } 162975584Sru | expr EQUALEQUAL expr 163075584Sru { $$ = ($1 == $3); } 163175584Sru | expr NOTEQUAL expr 163275584Sru { $$ = ($1 != $3); } 163375584Sru | expr ANDAND expr 163475584Sru { $$ = ($1 != 0.0 && $3 != 0.0); } 163575584Sru | expr OROR expr 163675584Sru { $$ = ($1 != 0.0 || $3 != 0.0); } 163775584Sru | '!' expr 163875584Sru { $$ = ($2 == 0.0); } 163975584Sru 164075584Sru ; 164175584Sru 164275584Sru%% 164375584Sru 164475584Sru/* bison defines const to be empty unless __STDC__ is defined, which it 164575584Sruisn't under cfront */ 164675584Sru 164775584Sru#ifdef const 164875584Sru#undef const 164975584Sru#endif 165075584Sru 165175584Srustatic struct { 165275584Sru const char *name; 165375584Sru double val; 165475584Sru int scaled; // non-zero if val should be multiplied by scale 165575584Sru} defaults_table[] = { 165675584Sru { "arcrad", .25, 1 }, 165775584Sru { "arrowht", .1, 1 }, 165875584Sru { "arrowwid", .05, 1 }, 165975584Sru { "circlerad", .25, 1 }, 166075584Sru { "boxht", .5, 1 }, 166175584Sru { "boxwid", .75, 1 }, 166275584Sru { "boxrad", 0.0, 1 }, 166375584Sru { "dashwid", .05, 1 }, 166475584Sru { "ellipseht", .5, 1 }, 166575584Sru { "ellipsewid", .75, 1 }, 166675584Sru { "moveht", .5, 1 }, 166775584Sru { "movewid", .5, 1 }, 166875584Sru { "lineht", .5, 1 }, 166975584Sru { "linewid", .5, 1 }, 167075584Sru { "textht", 0.0, 1 }, 167175584Sru { "textwid", 0.0, 1 }, 167275584Sru { "scale", 1.0, 0 }, 167375584Sru { "linethick", -1.0, 0 }, // in points 167475584Sru { "fillval", .5, 0 }, 167575584Sru { "arrowhead", 1.0, 0 }, 167675584Sru { "maxpswid", 8.5, 0 }, 167775584Sru { "maxpsht", 11.0, 0 }, 167875584Sru}; 167975584Sru 168075584Sruplace *lookup_label(const char *label) 168175584Sru{ 168275584Sru saved_state *state = current_saved_state; 168375584Sru PTABLE(place) *tbl = current_table; 168475584Sru for (;;) { 168575584Sru place *pl = tbl->lookup(label); 168675584Sru if (pl) 168775584Sru return pl; 168875584Sru if (!state) 168975584Sru return 0; 169075584Sru tbl = state->tbl; 169175584Sru state = state->prev; 169275584Sru } 169375584Sru} 169475584Sru 169575584Sruvoid define_label(const char *label, const place *pl) 169675584Sru{ 1697114402Sru place *p = new place[1]; 169875584Sru *p = *pl; 169975584Sru current_table->define(label, p); 170075584Sru} 170175584Sru 170275584Sruint lookup_variable(const char *name, double *val) 170375584Sru{ 170475584Sru place *pl = lookup_label(name); 170575584Sru if (pl) { 170675584Sru *val = pl->x; 170775584Sru return 1; 170875584Sru } 170975584Sru return 0; 171075584Sru} 171175584Sru 171275584Sruvoid define_variable(const char *name, double val) 171375584Sru{ 1714114402Sru place *p = new place[1]; 171575584Sru p->obj = 0; 171675584Sru p->x = val; 171775584Sru p->y = 0.0; 171875584Sru current_table->define(name, p); 171975584Sru if (strcmp(name, "scale") == 0) { 172075584Sru // When the scale changes, reset all scaled pre-defined variables to 172175584Sru // their default values. 172279543Sru for (unsigned int i = 0; 172379543Sru i < sizeof(defaults_table)/sizeof(defaults_table[0]); i++) 172475584Sru if (defaults_table[i].scaled) 172575584Sru define_variable(defaults_table[i].name, val*defaults_table[i].val); 172675584Sru } 172775584Sru} 172875584Sru 172975584Sru// called once only (not once per parse) 173075584Sru 173175584Sruvoid parse_init() 173275584Sru{ 173375584Sru current_direction = RIGHT_DIRECTION; 173475584Sru current_position.x = 0.0; 173575584Sru current_position.y = 0.0; 173675584Sru // This resets everything to its default value. 173775584Sru reset_all(); 173875584Sru} 173975584Sru 174075584Sruvoid reset(const char *nm) 174175584Sru{ 174279543Sru for (unsigned int i = 0; 174379543Sru i < sizeof(defaults_table)/sizeof(defaults_table[0]); i++) 174475584Sru if (strcmp(nm, defaults_table[i].name) == 0) { 174575584Sru double val = defaults_table[i].val; 174675584Sru if (defaults_table[i].scaled) { 174775584Sru double scale; 174875584Sru lookup_variable("scale", &scale); 174975584Sru val *= scale; 175075584Sru } 175175584Sru define_variable(defaults_table[i].name, val); 175275584Sru return; 175375584Sru } 175475584Sru lex_error("`%1' is not a predefined variable", nm); 175575584Sru} 175675584Sru 175775584Sruvoid reset_all() 175875584Sru{ 175975584Sru // We only have to explicitly reset the pre-defined variables that 176075584Sru // aren't scaled because `scale' is not scaled, and changing the 176175584Sru // value of `scale' will reset all the pre-defined variables that 176275584Sru // are scaled. 176379543Sru for (unsigned int i = 0; 176479543Sru i < sizeof(defaults_table)/sizeof(defaults_table[0]); i++) 176575584Sru if (!defaults_table[i].scaled) 176675584Sru define_variable(defaults_table[i].name, defaults_table[i].val); 176775584Sru} 176875584Sru 176975584Sru// called after each parse 177075584Sru 177175584Sruvoid parse_cleanup() 177275584Sru{ 177375584Sru while (current_saved_state != 0) { 177475584Sru delete current_table; 177575584Sru current_table = current_saved_state->tbl; 177675584Sru saved_state *tem = current_saved_state; 177775584Sru current_saved_state = current_saved_state->prev; 177875584Sru delete tem; 177975584Sru } 178075584Sru assert(current_table == &top_table); 178175584Sru PTABLE_ITERATOR(place) iter(current_table); 178275584Sru const char *key; 178375584Sru place *pl; 178475584Sru while (iter.next(&key, &pl)) 178575584Sru if (pl->obj != 0) { 178675584Sru position pos = pl->obj->origin(); 178775584Sru pl->obj = 0; 178875584Sru pl->x = pos.x; 178975584Sru pl->y = pos.y; 179075584Sru } 179175584Sru while (olist.head != 0) { 179275584Sru object *tem = olist.head; 179375584Sru olist.head = olist.head->next; 179475584Sru delete tem; 179575584Sru } 179675584Sru olist.tail = 0; 179775584Sru current_direction = RIGHT_DIRECTION; 179875584Sru current_position.x = 0.0; 179975584Sru current_position.y = 0.0; 180075584Sru} 180175584Sru 180275584Sruconst char *ordinal_postfix(int n) 180375584Sru{ 180475584Sru if (n < 10 || n > 20) 180575584Sru switch (n % 10) { 180675584Sru case 1: 180775584Sru return "st"; 180875584Sru case 2: 180975584Sru return "nd"; 181075584Sru case 3: 181175584Sru return "rd"; 181275584Sru } 181375584Sru return "th"; 181475584Sru} 181575584Sru 181675584Sruconst char *object_type_name(object_type type) 181775584Sru{ 181875584Sru switch (type) { 181975584Sru case BOX_OBJECT: 182075584Sru return "box"; 182175584Sru case CIRCLE_OBJECT: 182275584Sru return "circle"; 182375584Sru case ELLIPSE_OBJECT: 182475584Sru return "ellipse"; 182575584Sru case ARC_OBJECT: 182675584Sru return "arc"; 182775584Sru case SPLINE_OBJECT: 182875584Sru return "spline"; 182975584Sru case LINE_OBJECT: 183075584Sru return "line"; 183175584Sru case ARROW_OBJECT: 183275584Sru return "arrow"; 183375584Sru case MOVE_OBJECT: 183475584Sru return "move"; 183575584Sru case TEXT_OBJECT: 183675584Sru return "\"\""; 183775584Sru case BLOCK_OBJECT: 183875584Sru return "[]"; 183975584Sru case OTHER_OBJECT: 184075584Sru case MARK_OBJECT: 184175584Sru default: 184275584Sru break; 184375584Sru } 184475584Sru return "object"; 184575584Sru} 184675584Sru 184775584Srustatic char sprintf_buf[1024]; 184875584Sru 184975584Sruchar *format_number(const char *form, double n) 185075584Sru{ 185175584Sru if (form == 0) 185275584Sru form = "%g"; 1853104862Sru return do_sprintf(form, &n, 1); 185475584Sru} 185575584Sru 185675584Sruchar *do_sprintf(const char *form, const double *v, int nv) 185775584Sru{ 185875584Sru string result; 185975584Sru int i = 0; 186075584Sru string one_format; 186175584Sru while (*form) { 186275584Sru if (*form == '%') { 186375584Sru one_format += *form++; 186475584Sru for (; *form != '\0' && strchr("#-+ 0123456789.", *form) != 0; form++) 186575584Sru one_format += *form; 186675584Sru if (*form == '\0' || strchr("eEfgG%", *form) == 0) { 186775584Sru lex_error("bad sprintf format"); 186875584Sru result += one_format; 186975584Sru result += form; 187075584Sru break; 187175584Sru } 187275584Sru if (*form == '%') { 187375584Sru one_format += *form++; 187475584Sru one_format += '\0'; 1875104862Sru snprintf(sprintf_buf, sizeof(sprintf_buf), 1876104862Sru "%s", one_format.contents()); 187775584Sru } 187875584Sru else { 187975584Sru if (i >= nv) { 1880104862Sru lex_error("too few arguments to snprintf"); 188175584Sru result += one_format; 188275584Sru result += form; 188375584Sru break; 188475584Sru } 188575584Sru one_format += *form++; 188675584Sru one_format += '\0'; 1887104862Sru snprintf(sprintf_buf, sizeof(sprintf_buf), 1888104862Sru one_format.contents(), v[i++]); 188975584Sru } 189075584Sru one_format.clear(); 189175584Sru result += sprintf_buf; 189275584Sru } 189375584Sru else 189475584Sru result += *form++; 189575584Sru } 189675584Sru result += '\0'; 189775584Sru return strsave(result.contents()); 189875584Sru} 1899