1 %{
2 /*
3  * Grace - GRaphing, Advanced Computation and Exploration of data
4  *
5  * Home page: http://plasma-gate.weizmann.ac.il/Grace/
6  *
7  * Copyright (c) 1991-1995 Paul J Turner, Portland, OR
8  * Copyright (c) 1996-2003 Grace Development Team
9  *
10  * Maintained by Evgeny Stambulchik
11  *
12  *
13  *                           All Rights Reserved
14  *
15  *    This program is free software; you can redistribute it and/or modify
16  *    it under the terms of the GNU General Public License as published by
17  *    the Free Software Foundation; either version 2 of the License, or
18  *    (at your option) any later version.
19  *
20  *    This program is distributed in the hope that it will be useful,
21  *    but WITHOUT ANY WARRANTY; without even the implied warranty of
22  *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
23  *    GNU General Public License for more details.
24  *
25  *    You should have received a copy of the GNU General Public License
26  *    along with this program; if not, write to the Free Software
27  *    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
28  */
29 
30 /*
31  *
32  * evaluate expressions, commands, parameter files
33  *
34  */
35 
36 #include <config.h>
37 #include <cmath.h>
38 
39 #include <stdio.h>
40 #include <stdlib.h>
41 #include <unistd.h>
42 #include <string.h>
43 #include <ctype.h>
44 #if defined(HAVE_SYS_PARAM_H)
45 #  include <sys/param.h>
46 #endif
47 
48 /* bison not always handles it well itself */
49 #if defined(HAVE_ALLOCA_H)
50 #  include <alloca.h>
51 #endif
52 
53 #include "defines.h"
54 #include "globals.h"
55 #include "cephes/cephes.h"
56 #include "device.h"
57 #include "utils.h"
58 #include "files.h"
59 #include "graphs.h"
60 #include "graphutils.h"
61 #include "plotone.h"
62 #include "dlmodule.h"
63 #include "t1fonts.h"
64 #include "ssdata.h"
65 #include "protos.h"
66 #include "parser.h"
67 #include "mathstuff.h"
68 
69 #define MAX_PARS_STRING_LENGTH  4096
70 
71 #define CAST_DBL_TO_BOOL(x) (fabs(x) < 0.5 ? 0:1)
72 
73 typedef double (*ParserFnc)();
74 
75 extern graph *g;
76 
77 static double  s_result;    /* return value if a scalar expression is scanned*/
78 static grarr *v_result;    /* return value if a vector expression is scanned*/
79 
80 static int expr_parsed, vexpr_parsed;
81 
82 static int interr;
83 
84 static grarr freelist[100]; 	/* temporary vectors */
85 static int fcnt = 0;		/* number of the temporary vectors allocated */
86 
87 static target trgt_pool[100]; 	/* pool of temporary targets */
88 static int tgtn = 0;		/* number of the temporary targets used */
89 
90 int naxis = 0;	/* current axis */
91 static int curline, curbox, curellipse, curstring;
92 /* these guys attempt to avoid reentrancy problems */
93 static int gotparams = FALSE, gotread = FALSE, gotnlfit = FALSE;
94 int readxformat;
95 static int nlfit_gno, nlfit_setno, nlfit_nsteps;
96 static double *nlfit_warray = NULL;
97 
98 char batchfile[GR_MAXPATHLEN] = "",
99      paramfile[GR_MAXPATHLEN] = "",
100      readfile[GR_MAXPATHLEN] = "";
101 
102 static char f_string[MAX_PARS_STRING_LENGTH]; /* buffer for string to parse */
103 static int pos;
104 
105 /* the graph, set, and its length of the parser's current state */
106 static int whichgraph;
107 static int whichset;
108 
109 /* the graph and set of the left part of a vector assignment */
110 static int vasgn_gno;
111 static int vasgn_setno;
112 
113 static int alias_force = FALSE; /* controls whether aliases can override
114                                                        existing keywords */
115 
116 extern char print_file[];
117 extern char *close_input;
118 
119 static int filltype_obs;
120 
121 static int index_shift = 0;     /* 0 for C, 1 for F77 index notation */
122 
123 static void free_tmpvrbl(grarr *vrbl);
124 static void copy_vrbl(grarr *dest, grarr *src);
125 static int find_set_bydata(double *data, target *tgt);
126 
127 static int getcharstr(void);
128 static void ungetchstr(void);
129 static int follow(int expect, int ifyes, int ifno);
130 
131 static int yylex(void);
132 static int yyparse(void);
133 static void yyerror(char *s);
134 
135 static int findf(symtab_entry *keytable, char *s);
136 
137 /* Total (intrinsic + user-defined) list of functions and keywords */
138 symtab_entry *key;
139 
140 %}
141 
142 %union {
143     int     ival;
144     double  dval;
145     char   *sval;
146     double *dptr;
147     target *trgt;
148     grarr  *vrbl;
149 }
150 
151 %token KEY_VAR
152 %token KEY_VEC
153 
154 %token KEY_CONST
155 %token KEY_UNIT
156 %token KEY_FUNC_I
157 %token KEY_FUNC_D
158 %token KEY_FUNC_NN
159 %token KEY_FUNC_ND
160 %token KEY_FUNC_DD
161 %token KEY_FUNC_NND
162 %token KEY_FUNC_PPD
163 %token KEY_FUNC_PPPD
164 %token KEY_FUNC_PPPPD
165 %token KEY_FUNC_PPPPPD
166 
167 %token <ival> INDEX
168 %token <ival> DATE
169 
170 %token <dptr> VAR_D	 /* a (pointer to) double variable                                     */
171 %token <vrbl> VEC_D	 /* a (pointer to) double array variable                                     */
172 
173 %token <ival> CONSTANT	 /* a (double) constant                                     */
174 %token <ival> UCONSTANT	 /* a (double) unit constant                                */
175 %token <ival> FUNC_I	 /* a function of 1 int variable                            */
176 %token <ival> FUNC_D	 /* a function of 1 double variable                         */
177 %token <ival> FUNC_NN    /* a function of 2 int parameters                          */
178 %token <ival> FUNC_ND    /* a function of 1 int parameter and 1 double variable     */
179 %token <ival> FUNC_DD    /* a function of 2 double variables                        */
180 %token <ival> FUNC_NND   /* a function of 2 int parameters and 1 double variable    */
181 %token <ival> FUNC_PPD   /* a function of 2 double parameters and 1 double variable */
182 %token <ival> FUNC_PPPD  /* a function of 3 double parameters and 1 double variable */
183 %token <ival> FUNC_PPPPD /* a function of 4 double parameters and 1 double variable */
184 %token <ival> FUNC_PPPPPD/* a function of 5 double parameters and 1 double variable */
185 
186 %token <ival> ABOVE
187 %token <ival> ABSOLUTE
188 %token <ival> ALIAS
189 %token <ival> ALT
190 %token <ival> ALTXAXIS
191 %token <ival> ALTYAXIS
192 %token <ival> ANGLE
193 %token <ival> ANTIALIASING
194 %token <ival> APPEND
195 %token <ival> ARRANGE
196 %token <ival> ARROW
197 %token <ival> ASCENDING
198 %token <ival> ASPLINE
199 %token <ival> AUTO
200 %token <ival> AUTOSCALE
201 %token <ival> AUTOTICKS
202 %token <ival> AVALUE
203 %token <ival> AVG
204 %token <ival> BACKGROUND
205 %token <ival> BAR
206 %token <ival> BARDY
207 %token <ival> BARDYDY
208 %token <ival> BASELINE
209 %token <ival> BATCH
210 %token <ival> BEGIN
211 %token <ival> BELOW
212 %token <ival> BETWEEN
213 %token <ival> BLACKMAN
214 %token <ival> BLOCK
215 %token <ival> BOTH
216 %token <ival> BOTTOM
217 %token <ival> BOX
218 %token <ival> CD
219 %token <ival> CENTER
220 %token <ival> CHAR
221 %token <ival> CHART
222 %token <sval> CHRSTR
223 %token <ival> CLEAR
224 %token <ival> CLICK
225 %token <ival> CLIP
226 %token <ival> CLOSE
227 %token <ival> COEFFICIENTS
228 %token <ival> COLOR
229 %token <ival> COMMENT
230 %token <ival> COMPLEX
231 %token <ival> COMPUTING
232 %token <ival> CONSTRAINTS
233 %token <ival> COPY
234 %token <ival> CYCLE
235 %token <ival> DAYMONTH
236 %token <ival> DAYOFWEEKL
237 %token <ival> DAYOFWEEKS
238 %token <ival> DAYOFYEAR
239 %token <ival> DDMMYY
240 %token <ival> DECIMAL
241 %token <ival> DEF
242 %token <ival> DEFAULT
243 %token <ival> DEFINE
244 %token <ival> DEGREESLAT
245 %token <ival> DEGREESLON
246 %token <ival> DEGREESMMLAT
247 %token <ival> DEGREESMMLON
248 %token <ival> DEGREESMMSSLAT
249 %token <ival> DEGREESMMSSLON
250 %token <ival> DESCENDING
251 %token <ival> DESCRIPTION
252 %token <ival> DEVICE
253 %token <ival> DFT
254 %token <ival> DIFFERENCE
255 %token <ival> DISK
256 %token <ival> DOWN
257 %token <ival> DPI
258 %token <ival> DROP
259 %token <ival> DROPLINE
260 %token <ival> ECHO
261 %token <ival> ELLIPSE
262 %token <ival> ENGINEERING
263 %token <ival> ERRORBAR
264 %token <ival> EXIT
265 %token <ival> EXPONENTIAL
266 %token <ival> FFT
267 %token <ival> FILEP
268 %token <ival> FILL
269 %token <ival> FIT
270 %token <ival> FIXED
271 %token <ival> FIXEDPOINT
272 %token <ival> FLUSH
273 %token <ival> FOCUS
274 %token <ival> FOLLOWS
275 %token <ival> FONTP
276 %token <ival> FORCE
277 %token <ival> FORMAT
278 %token <ival> FORMULA
279 %token <ival> FRAMEP
280 %token <ival> FREE
281 %token <ival> FREQUENCY
282 %token <ival> FROM
283 %token <ival> GENERAL
284 %token <ival> GETP
285 %token <ival> GRAPH
286 %token <ival> GRAPHNO
287 %token <ival> GRID
288 %token <ival> HAMMING
289 %token <ival> HANNING
290 %token <ival> HARDCOPY
291 %token <ival> HBAR
292 %token <ival> HELP
293 %token <ival> HGAP
294 %token <ival> HIDDEN
295 %token <ival> HISTOGRAM
296 %token <ival> HMS
297 %token <ival> HORIZI
298 %token <ival> HORIZONTAL
299 %token <ival> HORIZO
300 %token <ival> ID
301 %token <ival> IFILTER
302 %token <ival> IMAX
303 %token <ival> IMIN
304 %token <ival> IN
305 %token <ival> INCREMENT
306 %token <ival> INOUT
307 %token <ival> INT
308 %token <ival> INTEGRATE
309 %token <ival> INTERPOLATE
310 %token <ival> INVDFT
311 %token <ival> INVERT
312 %token <ival> INVFFT
313 %token <ival> JUST
314 %token <ival> KILL
315 %token <ival> LABEL
316 %token <ival> LANDSCAPE
317 %token <ival> LAYOUT
318 %token <ival> LEFT
319 %token <ival> LEGEND
320 %token <ival> LENGTH
321 %token <ival> LINCONV
322 %token <ival> LINE
323 %token <ival> LINEAR
324 %token <ival> LINESTYLE
325 %token <ival> LINEWIDTH
326 %token <ival> LINK
327 %token <ival> LOAD
328 %token <ival> LOCTYPE
329 %token <ival> LOG
330 %token <ival> LOGARITHMIC
331 %token <ival> LOGIT
332 %token <ival> LOGX
333 %token <ival> LOGXY
334 %token <ival> LOGY
335 %token <ival> MAGIC
336 %token <ival> MAGNITUDE
337 %token <ival> MAJOR
338 %token <ival> MAP
339 %token <ival> MAXP
340 %token <ival> MESH
341 %token <ival> MINP
342 %token <ival> MINOR
343 %token <ival> MMDD
344 %token <ival> MMDDHMS
345 %token <ival> MMDDYY
346 %token <ival> MMDDYYHMS
347 %token <ival> MMSSLAT
348 %token <ival> MMSSLON
349 %token <ival> MMYY
350 %token <ival> MONTHDAY
351 %token <ival> MONTHL
352 %token <ival> MONTHS
353 %token <ival> MONTHSY
354 %token <ival> MOVE
355 %token <ival> NEGATE
356 %token <ival> NEW
357 %token <ival> NONE
358 %token <ival> NONLFIT
359 %token <ival> NORMAL
360 %token <ival> NXY
361 %token <ival> OFF
362 %token <ival> OFFSET
363 %token <ival> OFFSETX
364 %token <ival> OFFSETY
365 %token <ival> OFILTER
366 %token <ival> ON
367 %token <ival> ONREAD
368 %token <ival> OP
369 %token <ival> OPPOSITE
370 %token <ival> OUT
371 %token <ival> PAGE
372 %token <ival> PARA
373 %token <ival> PARAMETERS
374 %token <ival> PARZEN
375 %token <ival> PATTERN
376 %token <ival> PERIOD
377 %token <ival> PERP
378 %token <ival> PHASE
379 %token <ival> PIE
380 %token <ival> PIPE
381 %token <ival> PLACE
382 %token <ival> POINT
383 %token <ival> POLAR
384 %token <ival> POLYI
385 %token <ival> POLYO
386 %token <ival> POP
387 %token <ival> PORTRAIT
388 %token <ival> POWER
389 %token <ival> PREC
390 %token <ival> PREPEND
391 %token <ival> PRINT
392 %token <ival> PS
393 %token <ival> PUSH
394 %token <ival> PUTP
395 %token <ival> RAND
396 %token <ival> READ
397 %token <ival> REAL
398 %token <ival> RECIPROCAL
399 %token <ival> REDRAW
400 %token <ival> REFERENCE
401 %token <ival> REGNUM
402 %token <ival> REGRESS
403 %token <ival> RESIZE
404 %token <ival> RESTRICT
405 %token <ival> REVERSE
406 %token <ival> RIGHT
407 %token <ival> RISER
408 %token <ival> ROT
409 %token <ival> ROUNDED
410 %token <ival> RSUM
411 %token <ival> RULE
412 %token <ival> RUNAVG
413 %token <ival> RUNMAX
414 %token <ival> RUNMED
415 %token <ival> RUNMIN
416 %token <ival> RUNSTD
417 %token <ival> SAVEALL
418 %token <ival> SCALE
419 %token <ival> SCIENTIFIC
420 %token <ival> SCROLL
421 %token <ival> SD
422 %token <ival> SET
423 %token <ival> SETNUM
424 %token <ival> SFORMAT
425 %token <ival> SIGN
426 %token <ival> SIZE
427 %token <ival> SKIP
428 %token <ival> SLEEP
429 %token <ival> SMITH
430 %token <ival> SORT
431 %token <ival> SOURCE
432 %token <ival> SPEC
433 %token <ival> SPLINE
434 %token <ival> SPLIT
435 %token <ival> STACK
436 %token <ival> STACKED
437 %token <ival> STACKEDBAR
438 %token <ival> STACKEDHBAR
439 %token <ival> STAGGER
440 %token <ival> START
441 %token <ival> STOP
442 %token <ival> STRING
443 %token <ival> SUM
444 %token <ival> SUBTITLE
445 %token <ival> SWAP
446 %token <ival> SYMBOL
447 %token <ival> TARGET
448 %token <ival> TICKLABEL
449 %token <ival> TICKP
450 %token <ival> TICKSP
451 %token <ival> TIMER
452 %token <ival> TIMESTAMP
453 %token <ival> TITLE
454 %token <ival> TO
455 %token <ival> TOP
456 %token <ival> TRIANGULAR
457 %token <ival> TYPE
458 %token <ival> UP
459 %token <ival> UPDATEALL
460 %token <ival> USE
461 %token <ival> VERSION
462 %token <ival> VERTI
463 %token <ival> VERTICAL
464 %token <ival> VERTO
465 %token <ival> VGAP
466 %token <ival> VIEW
467 %token <ival> VX1
468 %token <ival> VX2
469 %token <ival> VXMAX
470 %token <ival> VY1
471 %token <ival> VY2
472 %token <ival> VYMAX
473 %token <ival> WELCH
474 %token <ival> WITH
475 %token <ival> WORLD
476 %token <ival> WRAP
477 %token <ival> WRITE
478 %token <ival> WX1
479 %token <ival> WX2
480 %token <ival> WY1
481 %token <ival> WY2
482 %token <ival> X_TOK
483 %token <ival> X0
484 %token <ival> X1
485 %token <ival> XAXES
486 %token <ival> XAXIS
487 %token <ival> XCOR
488 %token <ival> XMAX
489 %token <ival> XMIN
490 %token <ival> XY
491 %token <ival> XYAXES
492 %token <ival> XYBOXPLOT
493 %token <ival> XYCOLOR
494 %token <ival> XYCOLPAT
495 %token <ival> XYDX
496 %token <ival> XYDXDX
497 %token <ival> XYDXDXDYDY
498 %token <ival> XYDXDY
499 %token <ival> XYDY
500 %token <ival> XYDYDY
501 %token <ival> XYHILO
502 %token <ival> XYR
503 %token <ival> XYSIZE
504 %token <ival> XYSTRING
505 %token <ival> XYVMAP
506 %token <ival> XYZ
507 %token <ival> Y_TOK
508 %token <ival> Y0
509 %token <ival> Y1
510 %token <ival> Y2
511 %token <ival> Y3
512 %token <ival> Y4
513 %token <ival> YAXES
514 %token <ival> YAXIS
515 %token <ival> YEAR
516 %token <ival> YMAX
517 %token <ival> YMIN
518 %token <ival> YYMMDD
519 %token <ival> YYMMDDHMS
520 %token <ival> ZERO
521 %token <ival> ZNORM
522 
523 %token <ival> FITPARM
524 %token <ival> FITPMAX
525 %token <ival> FITPMIN
526 %token <dval> NUMBER
527 
528 %token <sval> NEW_TOKEN
529 
530 %type <ival> onoff
531 
532 %type <ival> selectgraph
533 %type <trgt> selectset
534 
535 %type <ival> pagelayout
536 %type <ival> pageorient
537 
538 %type <ival> regiontype
539 
540 %type <ival> color_select
541 %type <ival> pattern_select
542 %type <ival> font_select
543 
544 %type <ival> lines_select
545 %type <dval> linew_select
546 
547 %type <ival> graphtype
548 %type <ival> xytype
549 
550 %type <ival> scaletype
551 %type <ival> signchoice
552 
553 %type <ival> colpat_obs
554 %type <ival> direction
555 
556 %type <ival> formatchoice
557 %type <ival> inoutchoice
558 %type <ival> justchoice
559 
560 %type <ival> opchoice
561 %type <ival> opchoice_sel
562 %type <ival> opchoice_obs
563 %type <ival> opchoice_sel_obs
564 
565 %type <ival> worldview
566 
567 %type <ival> filtermethod
568 %type <ival> filtertype
569 
570 %type <ival> tickspectype
571 
572 %type <ival> sourcetype
573 
574 %type <ival> interpmethod
575 %type <ival> stattype
576 
577 %type <ival> datacolumn
578 
579 %type <ival> runtype
580 
581 %type <ival> ffttype
582 %type <ival> fourierdata
583 %type <ival> fourierloadx
584 %type <ival> fourierloady
585 %type <ival> windowtype
586 
587 %type <ival> nonlfitopts
588 
589 %type <ival> sortdir
590 %type <ival> sorton
591 
592 %type <ival> proctype
593 
594 %type <ival> indx
595 %type <ival> iexpr
596 %type <ival> nexpr
597 %type <sval> sexpr
598 %type <dval> jdate
599 %type <dval> jrawdate
600 %type <dval> expr
601 
602 %type <vrbl> array
603 %type <vrbl> lside_array
604 
605 %type <vrbl> vexpr
606 
607 /* Precedence */
608 %nonassoc '?' ':'
609 %left OR
610 %left AND
611 %nonassoc GT LT LE GE EQ NE
612 %right UCONSTANT
613 %left '+' '-'
614 %left '*' '/' '%'
615 %nonassoc UMINUS NOT	/* negation--unary minus */
616 %right '^'		/* exponentiation        */
617 %left '.'
618 
619 
620 %%
621 
622 full_list:
623         multi_list
624         | expr {
625             expr_parsed = TRUE;
626             s_result = $1;
627         }
628         | vexpr {
629             vexpr_parsed = TRUE;
630             v_result = $1;
631         }
632         ;
633 
634 multi_list:
635         list
636         | multi_list ';' list
637         ;
638 
639 list:
640 	/* empty */
641 	| parmset {}
642 	| parmset_obs {}
643 	| regionset {}
644 	| setaxis {}
645 	| set_setprop {}
646 	| actions {}
647 	| options {}
648 	| asgn {}
649 	| vasgn {}
650 	| defines {}
651 	| error {
652 	    return 1;
653 	}
654 	;
655 
656 
657 
658 expr:	NUMBER {
659 	    $$ = $1;
660 	}
661 	|  VAR_D {
662 	    $$ = *($1);
663 	}
664 	|  FITPARM {
665 	    $$ = nonl_parms[$1].value;
666 	}
667 	|  FITPMAX {
668 	    $$ = nonl_parms[$1].max;
669 	}
670 	|  FITPMIN {
671 	    $$ = nonl_parms[$1].min;
672 	}
673 	|  array indx {
674             if ($2 >= $1->length) {
675                 errmsg("Access beyond array bounds");
676                 return 1;
677             }
678             $$ = $1->data[$2];
679 	}
680 	| stattype '(' vexpr ')' {
681 	    double dummy, dummy2;
682             int idummy, ind, length = $3->length;
683 	    if ($3->data == NULL) {
684 		yyerror("NULL variable, check set type");
685 		return 1;
686 	    }
687 	    switch ($1) {
688 	    case MINP:
689 		$$ = vmin($3->data, length);
690 		break;
691 	    case MAXP:
692 		$$ = vmax($3->data, length);
693 		break;
694             case AVG:
695 		stasum($3->data, length, &$$, &dummy);
696                 break;
697             case SD:
698 		stasum($3->data, length, &dummy, &$$);
699                 break;
700             case SUM:
701 		stasum($3->data, length, &$$, &dummy);
702                 $$ *= length;
703                 break;
704             case IMIN:
705 		minmax($3->data, length, &dummy, &dummy2, &ind, &idummy);
706                 $$ = (double) ind;
707                 break;
708             case IMAX:
709 		minmax($3->data, length, &dummy, &dummy2, &idummy, &ind);
710                 $$ = (double) ind;
711                 break;
712 	    }
713 	}
714 	| INT '(' vexpr ',' vexpr ')' {
715 	    if ($3->length != $5->length) {
716 		yyerror("X and Y are of different length");
717 		return 1;
718             } else {
719                 $$ = trapint($3->data, $5->data, NULL, NULL, $3->length);
720             }
721 	}
722 	| array '.' LENGTH {
723 	    $$ = $1->length;
724 	}
725 	| selectset '.' LENGTH {
726 	    $$ = getsetlength($1->gno, $1->setno);
727 	}
728 	| selectset '.' ID {
729 	    $$ = $1->setno;
730 	}
731 	| selectgraph '.' ID {
732 	    $$ = $1;
733 	}
734 	| CONSTANT
735 	{
736             $$ = ((ParserFnc) (key[$1].data)) ();
737 	}
738 	| expr UCONSTANT
739 	{
740 	    $$ = $1 * ((ParserFnc) (key[$2].data)) ();
741 	}
742 	| RAND
743 	{
744 	    $$ = drand48();
745 	}
746 	| FUNC_I '(' iexpr ')'
747 	{
748 	    $$ = ((ParserFnc) (key[$1].data)) ($3);
749 	}
750 	| FUNC_D '(' expr ')'
751 	{
752 	    $$ = ((ParserFnc) (key[$1].data)) ($3);
753 	}
754 	| FUNC_ND '(' iexpr ',' expr ')'
755 	{
756 	    $$ = ((ParserFnc) (key[$1].data)) ($3, $5);
757 	}
758 	| FUNC_NN '(' iexpr ',' iexpr ')'
759 	{
760 	    $$ = ((ParserFnc) (key[$1].data)) ($3, $5);
761 	}
762 	| FUNC_DD '(' expr ',' expr ')'
763 	{
764 	    $$ = ((ParserFnc) (key[$1].data)) ($3, $5);
765 	}
766 	| FUNC_NND '(' iexpr ',' iexpr ',' expr ')'
767 	{
768 	    $$ = ((ParserFnc) (key[$1].data)) ($3, $5, $7);
769 	}
770 	| FUNC_PPD '(' expr ',' expr ',' expr ')'
771 	{
772 	    $$ = ((ParserFnc) (key[$1].data)) ($3, $5, $7);
773 	}
774 	| FUNC_PPPD '(' expr ',' expr ',' expr ',' expr ')'
775 	{
776 	    $$ = ((ParserFnc) (key[$1].data)) ($3, $5, $7, $9);
777 	}
778 	| FUNC_PPPPD '(' expr ',' expr ',' expr ',' expr ',' expr ')'
779 	{
780 	    $$ = ((ParserFnc) (key[$1].data)) ($3, $5, $7, $9, $11);
781 	}
782 	| FUNC_PPPPPD '(' expr ',' expr ',' expr ',' expr ',' expr ',' expr ')'
783 	{
784 	    $$ = ((ParserFnc) (key[$1].data)) ($3, $5, $7, $9, $11, $13);
785 	}
786 	| selectgraph '.' VX1 {
787 	    $$ = g[$1].v.xv1;
788 	}
789 	| selectgraph '.' VX2 {
790 	    $$ = g[$1].v.xv2;
791 	}
792 	| selectgraph '.' VY1 {
793 	    $$ = g[$1].v.yv1;
794 	}
795 	| selectgraph '.' VY2 {
796 	    $$ = g[$1].v.yv2;
797 	}
798 	| selectgraph '.' WX1 {
799 	    $$ = g[$1].w.xg1;
800 	}
801 	| selectgraph '.' WX2 {
802 	    $$ = g[$1].w.xg2;
803 	}
804 	| selectgraph '.' WY1 {
805 	    $$ = g[$1].w.yg1;
806 	}
807 	| selectgraph '.' WY2 {
808 	    $$ = g[$1].w.yg2;
809 	}
810 	| DATE '(' jdate ')' {
811             $$ = $3;
812 	}
813 	| DATE '(' iexpr ',' nexpr ',' nexpr ')' { /* yr, mo, day */
814 	    $$ = cal_and_time_to_jul($3, $5, $7, 12, 0, 0.0);
815 	}
816 	| DATE '(' iexpr ',' nexpr ',' nexpr ',' nexpr ',' nexpr ',' expr ')'
817 	{ /* yr, mo, day, hr, min, sec */
818 	    $$ = cal_and_time_to_jul($3, $5, $7, $9, $11, $13);
819 	}
820 	| VX1 {
821 	    if (!is_valid_gno(whichgraph)) {
822                 yyerror("No valid graph selected");
823                 return 1;
824             }
825             $$ = g[whichgraph].v.xv1;
826 	}
827 	| VX2 {
828 	    if (!is_valid_gno(whichgraph)) {
829                 yyerror("No valid graph selected");
830                 return 1;
831             }
832 	    $$ = g[whichgraph].v.xv2;
833 	}
834 	| VY1 {
835 	    if (!is_valid_gno(whichgraph)) {
836                 yyerror("No valid graph selected");
837                 return 1;
838             }
839 	    $$ = g[whichgraph].v.yv1;
840 	}
841 	| VY2 {
842 	    if (!is_valid_gno(whichgraph)) {
843                 yyerror("No valid graph selected");
844                 return 1;
845             }
846 	    $$ = g[whichgraph].v.yv2;
847 	}
848 	| WX1 {
849 	    if (!is_valid_gno(whichgraph)) {
850                 yyerror("No valid graph selected");
851                 return 1;
852             }
853 	    $$ = g[whichgraph].w.xg1;
854 	}
855 	| WX2 {
856 	    if (!is_valid_gno(whichgraph)) {
857                 yyerror("No valid graph selected");
858                 return 1;
859             }
860 	    $$ = g[whichgraph].w.xg2;
861 	}
862 	| WY1 {
863 	    if (!is_valid_gno(whichgraph)) {
864                 yyerror("No valid graph selected");
865                 return 1;
866             }
867 	    $$ = g[whichgraph].w.yg1;
868 	}
869 	| WY2 {
870 	    if (!is_valid_gno(whichgraph)) {
871                 yyerror("No valid graph selected");
872                 return 1;
873             }
874 	    $$ = g[whichgraph].w.yg2;
875 	}
876 	| VXMAX {
877 	    double vx, vy;
878             get_page_viewport(&vx, &vy);
879             $$ = vx;
880 	}
881 	| VYMAX {
882 	    double vx, vy;
883             get_page_viewport(&vx, &vy);
884             $$ = vy;
885 	}
886 	| '(' expr ')' {
887 	    $$ = $2;
888 	}
889 	| expr '+' expr {
890 	    $$ = $1 + $3;
891 	}
892 	| expr '-' expr {
893 	    $$ = $1 - $3;
894 	}
895 	| '-' expr %prec UMINUS {
896 	    $$ = -$2;
897 	}
898 	| '+' expr %prec UMINUS {
899 	    $$ = $2;
900 	}
901 	| expr '*' expr {
902 	    $$ = $1 * $3;
903 	}
904 	| expr '/' expr
905 	{
906 	    if ($3 != 0.0) {
907 		$$ = $1 / $3;
908 	    } else {
909 		yyerror("Divide by zero");
910 		return 1;
911 	    }
912 	}
913 	| expr '%' expr {
914 	    if ($3 != 0.0) {
915 		$$ = fmod($1, $3);
916 	    } else {
917 		yyerror("Divide by zero");
918 		return 1;
919 	    }
920 	}
921 	| expr '^' expr {
922 	    if ($1 < 0 && rint($3) != $3) {
923 		yyerror("Negative value raised to non-integer power");
924 		return 1;
925             } else if ($1 == 0.0 && $3 <= 0.0) {
926 		yyerror("Zero raised to non-positive power");
927 		return 1;
928             } else {
929                 $$ = pow($1, $3);
930             }
931 	}
932 	| expr '?' expr ':' expr {
933 	    $$ = $1 ? $3 : $5;
934 	}
935 	| expr GT expr {
936 	   $$ = ($1 > $3);
937 	}
938 	| expr LT expr  {
939 	   $$ = ($1 < $3);
940 	}
941 	| expr LE expr {
942 	   $$ = ($1 <= $3);
943 	}
944 	| expr GE expr {
945 	   $$ = ($1 >= $3);
946 	}
947 	| expr EQ expr {
948 	   $$ = ($1 == $3);
949 	}
950 	| expr NE expr {
951 	    $$ = ($1 != $3);
952 	}
953 	| expr AND expr {
954 	    $$ = $1 && $3;
955 	}
956 	| expr OR expr {
957 	    $$ = $1 || $3;
958 	}
959 	| NOT expr {
960 	    $$ = !($2);
961 	}
962 	;
963 
964 sexpr:	CHRSTR {
965             $$ = $1;
966 	}
967         | sexpr '.' sexpr {
968             $$ = concat_strings($1, $3);
969             xfree($3);
970         }
971         | sexpr '.' expr {
972             char buf[32];
973             set_locale_num(TRUE);
974             sprintf(buf, "%g", $3);
975             set_locale_num(FALSE);
976             $$ = concat_strings($1, buf);
977         }
978         ;
979 
980 iexpr:  expr {
981 	    int itmp = rint($1);
982             if (fabs(itmp - $1) > 1.e-6) {
983 		yyerror("Non-integer value supplied for integer");
984 		return 1;
985             }
986             $$ = itmp;
987         }
988         ;
989 
990 nexpr:	iexpr {
991             if ($1 < 0) {
992 		yyerror("Negative value supplied for non-negative");
993 		return 1;
994             }
995             $$ = $1;
996 	}
997         ;
998 
999 indx:	'[' iexpr ']' {
1000 	    int itmp = $2 - index_shift;
1001             if (itmp < 0) {
1002 		yyerror("Negative index");
1003 		return 1;
1004             }
1005             $$ = itmp;
1006 	}
1007         ;
1008 
1009 jdate:  expr {
1010             $$ = $1;
1011         }
1012         | sexpr {
1013             double jul;
1014             Dates_format dummy;
1015             if (parse_date($1, get_date_hint(), FALSE, &jul, &dummy)
1016                 == RETURN_SUCCESS) {
1017                 xfree($1);
1018                 $$ = jul;
1019             } else {
1020                 xfree($1);
1021 		yyerror("Invalid date");
1022 		return 1;
1023             }
1024         }
1025         ;
1026 
1027 jrawdate:  expr {
1028             $$ = $1;
1029         }
1030         | sexpr {
1031             double jul;
1032             Dates_format dummy;
1033             if (parse_date($1, get_date_hint(), TRUE, &jul, &dummy)
1034                 == RETURN_SUCCESS) {
1035                 xfree($1);
1036                 $$ = jul;
1037             } else {
1038                 xfree($1);
1039 		yyerror("Invalid date");
1040 		return 1;
1041             }
1042         }
1043         ;
1044 
1045 array:
1046 	VEC_D
1047 	{
1048             $$ = $1;
1049 	}
1050         | datacolumn
1051 	{
1052 	    double *ptr = getcol(vasgn_gno, vasgn_setno, $1);
1053             $$ = &freelist[fcnt++];
1054             $$->type = GRARR_SET;
1055             $$->data = ptr;
1056             if (ptr == NULL) {
1057                 errmsg("NULL variable - check set type");
1058                 return 1;
1059             } else {
1060                 $$->length = getsetlength(vasgn_gno, vasgn_setno);
1061             }
1062 	}
1063 	| selectset '.' datacolumn
1064 	{
1065 	    double *ptr = getcol($1->gno, $1->setno, $3);
1066             $$ = &freelist[fcnt++];
1067             $$->type = GRARR_SET;
1068             $$->data = ptr;
1069             if (ptr == NULL) {
1070                 errmsg("NULL variable - check set type");
1071                 return 1;
1072             } else {
1073                 $$->length = getsetlength($1->gno, $1->setno);
1074             }
1075 	}
1076         ;
1077 
1078 vexpr:
1079 	array
1080 	{
1081             $$ = $1;
1082 	}
1083 	| array '[' iexpr ':' iexpr ']'
1084 	{
1085             int start = $3 - index_shift, stop = $5 - index_shift;
1086             if (start < 0 || stop < start || stop >= $1->length) {
1087 		yyerror("Invalid index range");
1088             } else {
1089                 int len = stop - start + 1;
1090 	        double *ptr = xmalloc(len*SIZEOF_DOUBLE);
1091                 if ($$->data == NULL) {
1092                     yyerror("Not enough memory");
1093                 } else {
1094                     int i;
1095                     $$ = &freelist[fcnt++];
1096 	            $$->data = ptr;
1097                     $$->length = len;
1098                     $$->type = GRARR_TMP;
1099                     for (i = 0; i < len; i++) {
1100                         $$->data[i] = $1->data[i + $3];
1101                     }
1102                 }
1103             }
1104 	}
1105 	| MESH '(' nexpr ')'
1106 	{
1107             int len = $3;
1108             if (len < 1) {
1109                 yyerror("npoints must be > 0");
1110             } else {
1111                 double *ptr = allocate_index_data(len);
1112                 if (ptr == NULL) {
1113                     errmsg("Malloc failed");
1114                     return 1;
1115                 } else {
1116                     $$ = &freelist[fcnt++];
1117                     $$->type = GRARR_TMP;
1118                     $$->data = ptr;
1119                     $$->length = len;
1120                 }
1121             }
1122 	}
1123 	| MESH '(' expr ',' expr ',' nexpr ')'
1124 	{
1125             int len = $7;
1126             if (len < 2) {
1127                 yyerror("npoints must be > 1");
1128             } else {
1129                 double *ptr = allocate_mesh($3, $5, len);
1130                 if (ptr == NULL) {
1131                     errmsg("Malloc failed");
1132                     return 1;
1133                 } else {
1134                     $$ = &freelist[fcnt++];
1135                     $$->type = GRARR_TMP;
1136                     $$->data = ptr;
1137                     $$->length = len;
1138                 }
1139             }
1140 	}
1141 	| RAND '(' nexpr ')'
1142 	{
1143 	    int i;
1144             $$ = &freelist[fcnt++];
1145 	    $$->data = xmalloc($3*SIZEOF_DOUBLE);
1146             if ($$->data == NULL) {
1147                 errmsg("Not enough memory");
1148                 return 1;
1149             } else {
1150                 $$->length = $3;
1151                 $$->type = GRARR_TMP;
1152             }
1153             for (i = 0; i < $$->length; i++) {
1154 		$$->data[i] = drand48();
1155 	    }
1156 	}
1157 	| REGNUM '(' selectset ')'
1158 	{
1159 	    int rtype, i, len;
1160             char *rarray;
1161 
1162             rtype = RESTRICT_REG0 + $1;
1163 
1164 	    if (get_restriction_array($3->gno, $3->setno,
1165                 rtype, FALSE, &rarray) != RETURN_SUCCESS) {
1166                 errmsg("Error in region evaluation");
1167                 return 1;
1168 	    }
1169 
1170             len = getsetlength($3->gno, $3->setno);
1171             $$ = &freelist[fcnt++];
1172 	    $$->data = xmalloc(len*SIZEOF_DOUBLE);
1173             if ($$->data == NULL) {
1174                 errmsg("Not enough memory");
1175                 return 1;
1176             } else {
1177                 $$->length = len;
1178                 $$->type = GRARR_TMP;
1179             }
1180             for (i = 0; i < $$->length; i++) {
1181 		$$->data[i] = rarray[i];
1182 	    }
1183 
1184             xfree(rarray);
1185 	}
1186 	| RSUM '(' vexpr ')'
1187 	{
1188             int i;
1189             $$ = &freelist[fcnt++];
1190             copy_vrbl($$, $3);
1191             $$->type = GRARR_TMP;
1192             for (i = 1; i < $$->length; i++) {
1193                 $$->data[i] += $$->data[i - 1];
1194             }
1195 	}
1196 	| FUNC_I '(' vexpr ')'
1197 	{
1198 	    int i;
1199             $$ = &freelist[fcnt++];
1200 	    copy_vrbl($$, $3);
1201             $$->type = GRARR_TMP;
1202 	    for (i = 0; i < $$->length; i++) {
1203 		$$->data[i] = ((ParserFnc) (key[$1].data)) ((int) ($3->data[i]));
1204 	    }
1205 	}
1206 	| FUNC_D '(' vexpr ')'
1207 	{
1208 	    int i;
1209             $$ = &freelist[fcnt++];
1210 	    copy_vrbl($$, $3);
1211             $$->type = GRARR_TMP;
1212 	    for (i = 0; i < $$->length; i++) {
1213 		$$->data[i] = ((ParserFnc) (key[$1].data)) (($3->data[i]));
1214 	    }
1215 	}
1216 	| FUNC_DD '(' vexpr ',' vexpr ')'
1217 	{
1218 	    int i;
1219 	    if ($3->length != $5->length) {
1220                 errmsg("Can't operate on vectors of different lengths");
1221                 return 1;
1222             }
1223             $$ = &freelist[fcnt++];
1224 	    copy_vrbl($$, $3);
1225             $$->type = GRARR_TMP;
1226 
1227 	    for (i = 0; i < $$->length; i++) {
1228 		$$->data[i] = ((ParserFnc) (key[$1].data)) ($3->data[i], $5->data[i]);
1229 	    }
1230 	}
1231 	| FUNC_DD '(' expr ',' vexpr ')'
1232 	{
1233 	    int i;
1234             $$ = &freelist[fcnt++];
1235 	    copy_vrbl($$, $5);
1236             $$->type = GRARR_TMP;
1237 
1238 	    for (i = 0; i < $$->length; i++) {
1239 		$$->data[i] = ((ParserFnc) (key[$1].data)) ($3, $5->data[i]);
1240 	    }
1241 	}
1242 	| FUNC_DD '(' vexpr ',' expr ')'
1243 	{
1244 	    int i;
1245             $$ = &freelist[fcnt++];
1246 	    copy_vrbl($$, $3);
1247             $$->type = GRARR_TMP;
1248 
1249 	    for (i = 0; i < $$->length; i++) {
1250 		$$->data[i] = ((ParserFnc) (key[$1].data)) ($3->data[i], $5);
1251 	    }
1252 	}
1253 	| FUNC_ND '(' iexpr ',' vexpr ')'
1254 	{
1255 	    int i;
1256             $$ = &freelist[fcnt++];
1257 	    copy_vrbl($$, $5);
1258             $$->type = GRARR_TMP;
1259 
1260 	    for (i = 0; i < $$->length; i++) {
1261 		$$->data[i] = ((ParserFnc) (key[$1].data)) ($3, $5->data[i]);
1262 	    }
1263 	}
1264 	| FUNC_NND '(' iexpr ',' iexpr ',' vexpr ')'
1265 	{
1266 	    int i;
1267             $$ = &freelist[fcnt++];
1268 	    copy_vrbl($$, $7);
1269             $$->type = GRARR_TMP;
1270 
1271 	    for (i = 0; i < $$->length; i++) {
1272 		$$->data[i] = ((ParserFnc) (key[$1].data)) ($3, $5, $7->data[i]);
1273 	    }
1274 	}
1275 	| FUNC_PPD '(' expr ',' expr ',' vexpr ')'
1276 	{
1277 	    int i;
1278             $$ = &freelist[fcnt++];
1279 	    copy_vrbl($$, $7);
1280             $$->type = GRARR_TMP;
1281 
1282 	    for (i = 0; i < $$->length; i++) {
1283 		$$->data[i] = ((ParserFnc) (key[$1].data)) ($3, $5, $7->data[i]);
1284 	    }
1285 	}
1286 	| FUNC_PPPD '(' expr ',' expr ',' expr ',' vexpr ')'
1287 	{
1288 	    int i;
1289             $$ = &freelist[fcnt++];
1290 	    copy_vrbl($$, $9);
1291             $$->type = GRARR_TMP;
1292 
1293 	    for (i = 0; i < $$->length; i++) {
1294 		$$->data[i] = ((ParserFnc) (key[$1].data)) ($3, $5, $7, $9->data[i]);
1295 	    }
1296 	}
1297 	| FUNC_PPPPD '(' expr ',' expr ',' expr ',' expr ',' vexpr ')'
1298 	{
1299 	    int i;
1300             $$ = &freelist[fcnt++];
1301 	    copy_vrbl($$, $11);
1302             $$->type = GRARR_TMP;
1303 
1304 	    for (i = 0; i < $$->length; i++) {
1305 		$$->data[i] = ((ParserFnc) (key[$1].data)) ($3, $5, $7, $9, $11->data[i]);
1306 	    }
1307 	}
1308 	| FUNC_PPPPPD '(' expr ',' expr ',' expr ',' expr ',' expr ',' vexpr ')'
1309 	{
1310 	    int i;
1311             $$ = &freelist[fcnt++];
1312 	    copy_vrbl($$, $13);
1313             $$->type = GRARR_TMP;
1314 
1315 	    for (i = 0; i < $$->length; i++) {
1316 		$$->data[i] = ((ParserFnc) (key[$1].data)) ($3, $5, $7, $9, $11, $13->data[i]);
1317 	    }
1318 	}
1319 	| vexpr '+' vexpr
1320 	{
1321 	    int i;
1322 	    if ($1->length != $3->length) {
1323                 errmsg("Can't operate on vectors of different lengths");
1324                 return 1;
1325             }
1326             $$ = &freelist[fcnt++];
1327 	    copy_vrbl($$, $1);
1328             $$->type = GRARR_TMP;
1329 
1330 	    for (i = 0; i < $$->length; i++) {
1331 		$$->data[i] = $1->data[i] + $3->data[i];
1332 	    }
1333 	}
1334 	| vexpr '+' expr
1335 	{
1336 	    int i;
1337             $$ = &freelist[fcnt++];
1338 	    copy_vrbl($$, $1);
1339             $$->type = GRARR_TMP;
1340 
1341 	    for (i = 0; i < $$->length; i++) {
1342 		$$->data[i] = $1->data[i] + $3;
1343 	    }
1344 	}
1345 	| expr '+' vexpr
1346 	{
1347 	    int i;
1348             $$ = &freelist[fcnt++];
1349 	    copy_vrbl($$, $3);
1350             $$->type = GRARR_TMP;
1351 
1352 	    for (i = 0; i < $$->length; i++) {
1353 		$$->data[i] = $1 + $3->data[i];
1354 	    }
1355 	}
1356 	| vexpr '-' vexpr
1357 	{
1358 	    int i;
1359 	    if ($1->length != $3->length) {
1360                 errmsg("Can't operate on vectors of different lengths");
1361                 return 1;
1362             }
1363             $$ = &freelist[fcnt++];
1364 	    copy_vrbl($$, $1);
1365             $$->type = GRARR_TMP;
1366 
1367 	    for (i = 0; i < $$->length; i++) {
1368 		$$->data[i] = $1->data[i] - $3->data[i];
1369 	    }
1370 	}
1371 	| vexpr '-' expr
1372 	{
1373 	    int i;
1374             $$ = &freelist[fcnt++];
1375 	    copy_vrbl($$, $1);
1376             $$->type = GRARR_TMP;
1377 
1378 	    for (i = 0; i < $$->length; i++) {
1379 		$$->data[i] = $1->data[i] - $3;
1380 	    }
1381 	}
1382 	| expr '-' vexpr
1383 	{
1384 	    int i;
1385             $$ = &freelist[fcnt++];
1386 	    copy_vrbl($$, $3);
1387             $$->type = GRARR_TMP;
1388 
1389 	    for (i = 0; i < $$->length; i++) {
1390 		$$->data[i] = $1 - $3->data[i];
1391 	    }
1392 	}
1393 	| vexpr '*' vexpr
1394 	{
1395 	    int i;
1396 	    if ($1->length != $3->length) {
1397                 errmsg("Can't operate on vectors of different lengths");
1398                 return 1;
1399             }
1400             $$ = &freelist[fcnt++];
1401 	    copy_vrbl($$, $1);
1402             $$->type = GRARR_TMP;
1403 
1404 	    for (i = 0; i < $$->length; i++) {
1405 		$$->data[i] = $1->data[i] * $3->data[i];
1406 	    }
1407 	}
1408 	| vexpr '*' expr
1409 	{
1410 	    int i;
1411             $$ = &freelist[fcnt++];
1412 	    copy_vrbl($$, $1);
1413             $$->type = GRARR_TMP;
1414 
1415 	    for (i = 0; i < $$->length; i++) {
1416 		$$->data[i] = $1->data[i] * $3;
1417 	    }
1418 	}
1419 	| expr '*' vexpr
1420 	{
1421 	    int i;
1422             $$ = &freelist[fcnt++];
1423 	    copy_vrbl($$, $3);
1424             $$->type = GRARR_TMP;
1425 
1426 	    for (i = 0; i < $$->length; i++) {
1427 		$$->data[i] = $1 * $3->data[i];
1428 	    }
1429 	}
1430 	| vexpr '/' vexpr
1431 	{
1432 	    int i;
1433 	    if ($1->length != $3->length) {
1434                 errmsg("Can't operate on vectors of different lengths");
1435                 return 1;
1436             }
1437             $$ = &freelist[fcnt++];
1438 	    copy_vrbl($$, $1);
1439             $$->type = GRARR_TMP;
1440 
1441 	    for (i = 0; i < $$->length; i++) {
1442 		if ($3->data[i] == 0.0) {
1443                     errmsg("Divide by zero");
1444                     return 1;
1445                 }
1446                 $$->data[i] = $1->data[i] / $3->data[i];
1447 	    }
1448 	}
1449 	| vexpr '/' expr
1450 	{
1451 	    int i;
1452 	    if ($3 == 0.0) {
1453                 errmsg("Divide by zero");
1454                 return 1;
1455             }
1456             $$ = &freelist[fcnt++];
1457 	    copy_vrbl($$, $1);
1458             $$->type = GRARR_TMP;
1459 
1460 	    for (i = 0; i < $$->length; i++) {
1461 		$$->data[i] = $1->data[i] / $3;
1462 	    }
1463 	}
1464 	| expr '/' vexpr
1465 	{
1466 	    int i;
1467             $$ = &freelist[fcnt++];
1468 	    copy_vrbl($$, $3);
1469             $$->type = GRARR_TMP;
1470 
1471 	    for (i = 0; i < $$->length; i++) {
1472 		if ($3->data[i] == 0.0) {
1473                     errmsg("Divide by zero");
1474                     return 1;
1475                 }
1476 		$$->data[i] = $1 / $3->data[i];
1477 	    }
1478 	}
1479 	| vexpr '%' vexpr
1480 	{
1481 	    int i;
1482 	    if ($1->length != $3->length) {
1483                 errmsg("Can't operate on vectors of different lengths");
1484                 return 1;
1485             }
1486             $$ = &freelist[fcnt++];
1487 	    copy_vrbl($$, $1);
1488             $$->type = GRARR_TMP;
1489 
1490 	    for (i = 0; i < $$->length; i++) {
1491 		if ($3->data[i] == 0.0) {
1492                     errmsg("Divide by zero");
1493                     return 1;
1494                 } else {
1495                     $$->data[i] = fmod($1->data[i], $3->data[i]);
1496                 }
1497 	    }
1498 	}
1499 	| vexpr '%' expr
1500 	{
1501 	    int i;
1502 	    if ($3 == 0.0) {
1503                 errmsg("Divide by zero");
1504                 return 1;
1505             }
1506             $$ = &freelist[fcnt++];
1507 	    copy_vrbl($$, $1);
1508             $$->type = GRARR_TMP;
1509 
1510 	    for (i = 0; i < $$->length; i++) {
1511 		$$->data[i] = fmod($1->data[i], $3);
1512 	    }
1513 	}
1514 	| expr '%' vexpr
1515 	{
1516 	    int i;
1517             $$ = &freelist[fcnt++];
1518 	    copy_vrbl($$, $3);
1519             $$->type = GRARR_TMP;
1520 
1521 	    for (i = 0; i < $$->length; i++) {
1522 		if ($3->data[i] == 0.0) {
1523                     errmsg("Divide by zero");
1524                     return 1;
1525                 } else {
1526 		    $$->data[i] = fmod($1, $3->data[i]);
1527                 }
1528 	    }
1529 	}
1530 	| vexpr '^' vexpr
1531 	{
1532 	    int i;
1533 	    if ($1->length != $3->length) {
1534                 errmsg("Can't operate on vectors of different lengths");
1535                 return 1;
1536             }
1537             $$ = &freelist[fcnt++];
1538 	    copy_vrbl($$, $1);
1539             $$->type = GRARR_TMP;
1540 
1541 	    for (i = 0; i < $$->length; i++) {
1542 	        if ($1->data[i] < 0 && rint($3->data[i]) != $3->data[i]) {
1543 	            yyerror("Negative value raised to non-integer power");
1544 	            return 1;
1545                 } else if ($1->data[i] == 0.0 && $3->data[i] <= 0.0) {
1546 	            yyerror("Zero raised to non-positive power");
1547 	            return 1;
1548                 } else {
1549                     $$->data[i] = pow($1->data[i], $3->data[i]);
1550                 }
1551 	    }
1552 	}
1553 	| vexpr '^' expr
1554 	{
1555 	    int i;
1556             $$ = &freelist[fcnt++];
1557 	    copy_vrbl($$, $1);
1558             $$->type = GRARR_TMP;
1559 
1560 	    for (i = 0; i < $$->length; i++) {
1561 	        if ($1->data[i] < 0 && rint($3) != $3) {
1562 	            yyerror("Negative value raised to non-integer power");
1563 	            return 1;
1564                 } else if ($1->data[i] == 0.0 && $3 <= 0.0) {
1565 	            yyerror("Zero raised to non-positive power");
1566 	            return 1;
1567                 } else {
1568                     $$->data[i] = pow($1->data[i], $3);
1569                 }
1570 	    }
1571 	}
1572 	| expr '^' vexpr
1573 	{
1574 	    int i;
1575             $$ = &freelist[fcnt++];
1576 	    copy_vrbl($$, $3);
1577             $$->type = GRARR_TMP;
1578 
1579 	    for (i = 0; i < $$->length; i++) {
1580 	        if ($1 < 0 && rint($3->data[i]) != $3->data[i]) {
1581 	            yyerror("Negative value raised to non-integer power");
1582 	            return 1;
1583                 } else if ($1 == 0.0 && $3->data[i] <= 0.0) {
1584 	            yyerror("Zero raised to non-positive power");
1585 	            return 1;
1586                 } else {
1587                     $$->data[i] = pow($1, $3->data[i]);
1588                 }
1589 	    }
1590 	}
1591 	| vexpr UCONSTANT
1592 	{
1593 	    int i;
1594             $$ = &freelist[fcnt++];
1595 	    copy_vrbl($$, $1);
1596             $$->type = GRARR_TMP;
1597 	    for (i = 0; i < $$->length; i++) {
1598 		$$->data[i] = $1->data[i] * ((ParserFnc) (key[$2].data)) ();
1599 	    }
1600 	}
1601 	| vexpr '?' expr ':' expr {
1602             int i;
1603             $$ = &freelist[fcnt++];
1604 	    copy_vrbl($$, $1);
1605             $$->type = GRARR_TMP;
1606             for (i = 0; i < $$->length; i++) {
1607                 $$->data[i] = CAST_DBL_TO_BOOL($1->data[i]) ? $3 : $5;
1608             }
1609 	}
1610 	| vexpr '?' expr ':' vexpr {
1611             int i;
1612 	    if ($1->length != $5->length) {
1613                 errmsg("Can't operate on vectors of different lengths");
1614                 return 1;
1615             }
1616             $$ = &freelist[fcnt++];
1617 	    copy_vrbl($$, $1);
1618             $$->type = GRARR_TMP;
1619             for (i = 0; i < $$->length; i++) {
1620                 $$->data[i] = CAST_DBL_TO_BOOL($1->data[i]) ? $3 : $5->data[i];
1621             }
1622 	}
1623 	| vexpr '?' vexpr ':' expr {
1624             int i;
1625 	    if ($1->length != $3->length) {
1626                 errmsg("Can't operate on vectors of different lengths");
1627                 return 1;
1628             }
1629             $$ = &freelist[fcnt++];
1630 	    copy_vrbl($$, $1);
1631             $$->type = GRARR_TMP;
1632             for (i = 0; i < $$->length; i++) {
1633                 $$->data[i] = CAST_DBL_TO_BOOL($1->data[i]) ? $3->data[i] : $5;
1634             }
1635 	}
1636 	| vexpr '?' vexpr ':' vexpr {
1637             int i;
1638 	    if ($1->length != $5->length || $1->length != $3->length) {
1639                 errmsg("Can't operate on vectors of different lengths");
1640                 return 1;
1641             }
1642             $$ = &freelist[fcnt++];
1643 	    copy_vrbl($$, $1);
1644             $$->type = GRARR_TMP;
1645             for (i = 0; i < $$->length; i++) {
1646                 $$->data[i] = CAST_DBL_TO_BOOL($1->data[i]) ? $3->data[i] : $5->data[i];
1647             }
1648 	}
1649 	| vexpr OR vexpr
1650 	{
1651 	    int i;
1652 	    if ($1->length != $3->length) {
1653                 errmsg("Can't operate on vectors of different lengths");
1654                 return 1;
1655             }
1656             $$ = &freelist[fcnt++];
1657 	    copy_vrbl($$, $1);
1658             $$->type = GRARR_TMP;
1659 
1660 	    for (i = 0; i < $$->length; i++) {
1661 		$$->data[i] = $1->data[i] || $3->data[i];
1662 	    }
1663 	}
1664 	| vexpr OR expr
1665 	{
1666 	    int i;
1667             $$ = &freelist[fcnt++];
1668 	    copy_vrbl($$, $1);
1669             $$->type = GRARR_TMP;
1670 
1671 	    for (i = 0; i < $$->length; i++) {
1672 		$$->data[i] = $1->data[i] || $3;
1673 	    }
1674 	}
1675 	| expr OR vexpr
1676 	{
1677 	    int i;
1678             $$ = &freelist[fcnt++];
1679 	    copy_vrbl($$, $3);
1680             $$->type = GRARR_TMP;
1681 
1682 	    for (i = 0; i < $$->length; i++) {
1683 		$$->data[i] = $1 || $3->data[i];
1684 	    }
1685 	}
1686 	| vexpr AND vexpr
1687 	{
1688 	    int i;
1689 	    if ($1->length != $3->length) {
1690                 errmsg("Can't operate on vectors of different lengths");
1691                 return 1;
1692             }
1693             $$ = &freelist[fcnt++];
1694 	    copy_vrbl($$, $1);
1695             $$->type = GRARR_TMP;
1696 
1697 	    for (i = 0; i < $$->length; i++) {
1698 		$$->data[i] = $1->data[i] && $3->data[i];
1699 	    }
1700 	}
1701 	| vexpr AND expr
1702 	{
1703 	    int i;
1704             $$ = &freelist[fcnt++];
1705 	    copy_vrbl($$, $1);
1706             $$->type = GRARR_TMP;
1707 
1708 	    for (i = 0; i < $$->length; i++) {
1709 		$$->data[i] = $1->data[i] && $3;
1710 	    }
1711 	}
1712 	| expr AND vexpr
1713 	{
1714 	    int i;
1715             $$ = &freelist[fcnt++];
1716 	    copy_vrbl($$, $3);
1717             $$->type = GRARR_TMP;
1718 
1719 	    for (i = 0; i < $$->length; i++) {
1720 		$$->data[i] = $1 && $3->data[i];
1721 	    }
1722 	}
1723 	| vexpr GT vexpr
1724 	{
1725 	    int i;
1726 	    if ($1->length != $3->length) {
1727                 errmsg("Can't operate on vectors of different lengths");
1728                 return 1;
1729             }
1730             $$ = &freelist[fcnt++];
1731 	    copy_vrbl($$, $1);
1732             $$->type = GRARR_TMP;
1733 
1734 	    for (i = 0; i < $$->length; i++) {
1735 		$$->data[i] = ($1->data[i] > $3->data[i]);
1736 	    }
1737 	}
1738 	| vexpr GT expr
1739 	{
1740 	    int i;
1741             $$ = &freelist[fcnt++];
1742 	    copy_vrbl($$, $1);
1743             $$->type = GRARR_TMP;
1744 
1745 	    for (i = 0; i < $$->length; i++) {
1746 		$$->data[i] = ($1->data[i] > $3);
1747 	    }
1748 	}
1749 	| expr GT vexpr
1750 	{
1751 	    int i;
1752             $$ = &freelist[fcnt++];
1753 	    copy_vrbl($$, $3);
1754             $$->type = GRARR_TMP;
1755 
1756 	    for (i = 0; i < $$->length; i++) {
1757 		$$->data[i] = ($1 > $3->data[i]);
1758 	    }
1759 	}
1760 	| vexpr LT vexpr
1761 	{
1762 	    int i;
1763 	    if ($1->length != $3->length) {
1764                 errmsg("Can't operate on vectors of different lengths");
1765                 return 1;
1766             }
1767             $$ = &freelist[fcnt++];
1768 	    copy_vrbl($$, $1);
1769             $$->type = GRARR_TMP;
1770 
1771 	    for (i = 0; i < $$->length; i++) {
1772 		$$->data[i] = ($1->data[i] < $3->data[i]);
1773 	    }
1774 	}
1775 	| vexpr LT expr
1776 	{
1777 	    int i;
1778             $$ = &freelist[fcnt++];
1779 	    copy_vrbl($$, $1);
1780             $$->type = GRARR_TMP;
1781 
1782 	    for (i = 0; i < $$->length; i++) {
1783 		$$->data[i] = ($1->data[i] < $3);
1784 	    }
1785 	}
1786 	| expr LT vexpr
1787 	{
1788 	    int i;
1789             $$ = &freelist[fcnt++];
1790 	    copy_vrbl($$, $3);
1791             $$->type = GRARR_TMP;
1792 
1793 	    for (i = 0; i < $$->length; i++) {
1794 		$$->data[i] = ($1 < $3->data[i]);
1795 	    }
1796 	}
1797 	| vexpr GE vexpr
1798 	{
1799 	    int i;
1800 	    if ($1->length != $3->length) {
1801                 errmsg("Can't operate on vectors of different lengths");
1802                 return 1;
1803             }
1804             $$ = &freelist[fcnt++];
1805 	    copy_vrbl($$, $1);
1806             $$->type = GRARR_TMP;
1807 
1808 	    for (i = 0; i < $$->length; i++) {
1809 		$$->data[i] = ($1->data[i] >= $3->data[i]);
1810 	    }
1811 	}
1812 	| vexpr GE expr
1813 	{
1814 	    int i;
1815             $$ = &freelist[fcnt++];
1816 	    copy_vrbl($$, $1);
1817             $$->type = GRARR_TMP;
1818 
1819 	    for (i = 0; i < $$->length; i++) {
1820 		$$->data[i] = ($1->data[i] >= $3);
1821 	    }
1822 	}
1823 	| expr GE vexpr
1824 	{
1825 	    int i;
1826             $$ = &freelist[fcnt++];
1827 	    copy_vrbl($$, $3);
1828             $$->type = GRARR_TMP;
1829 
1830 	    for (i = 0; i < $$->length; i++) {
1831 		$$->data[i] = ($1 >= $3->data[i]);
1832 	    }
1833 	}
1834 	| vexpr LE vexpr
1835 	{
1836 	    int i;
1837 	    if ($1->length != $3->length) {
1838                 errmsg("Can't operate on vectors of different lengths");
1839                 return 1;
1840             }
1841             $$ = &freelist[fcnt++];
1842 	    copy_vrbl($$, $1);
1843             $$->type = GRARR_TMP;
1844 
1845 	    for (i = 0; i < $$->length; i++) {
1846 		$$->data[i] = ($1->data[i] <= $3->data[i]);
1847 	    }
1848 	}
1849 	| vexpr LE expr
1850 	{
1851 	    int i;
1852             $$ = &freelist[fcnt++];
1853 	    copy_vrbl($$, $1);
1854             $$->type = GRARR_TMP;
1855 
1856 	    for (i = 0; i < $$->length; i++) {
1857 		$$->data[i] = ($1->data[i] <= $3);
1858 	    }
1859 	}
1860 	| expr LE vexpr
1861 	{
1862 	    int i;
1863             $$ = &freelist[fcnt++];
1864 	    copy_vrbl($$, $3);
1865             $$->type = GRARR_TMP;
1866 
1867 	    for (i = 0; i < $$->length; i++) {
1868 		$$->data[i] = ($1 <= $3->data[i]);
1869 	    }
1870 	}
1871 	| vexpr EQ vexpr
1872 	{
1873 	    int i;
1874 	    if ($1->length != $3->length) {
1875                 errmsg("Can't operate on vectors of different lengths");
1876                 return 1;
1877             }
1878             $$ = &freelist[fcnt++];
1879 	    copy_vrbl($$, $1);
1880             $$->type = GRARR_TMP;
1881 
1882 	    for (i = 0; i < $$->length; i++) {
1883 		$$->data[i] = ($1->data[i] == $3->data[i]);
1884 	    }
1885 	}
1886 	| vexpr EQ expr
1887 	{
1888 	    int i;
1889             $$ = &freelist[fcnt++];
1890 	    copy_vrbl($$, $1);
1891             $$->type = GRARR_TMP;
1892 
1893 	    for (i = 0; i < $$->length; i++) {
1894 		$$->data[i] = ($1->data[i] == $3);
1895 	    }
1896 	}
1897 	| expr EQ vexpr
1898 	{
1899 	    int i;
1900             $$ = &freelist[fcnt++];
1901 	    copy_vrbl($$, $3);
1902             $$->type = GRARR_TMP;
1903 
1904 	    for (i = 0; i < $$->length; i++) {
1905 		$$->data[i] = ($1 == $3->data[i]);
1906 	    }
1907 	}
1908 	| vexpr NE vexpr
1909 	{
1910 	    int i;
1911 	    if ($1->length != $3->length) {
1912                 errmsg("Can't operate on vectors of different lengths");
1913                 return 1;
1914             }
1915             $$ = &freelist[fcnt++];
1916 	    copy_vrbl($$, $1);
1917             $$->type = GRARR_TMP;
1918 
1919 	    for (i = 0; i < $$->length; i++) {
1920 		$$->data[i] = ($1->data[i] != $3->data[i]);
1921 	    }
1922 	}
1923 	| vexpr NE expr
1924 	{
1925 	    int i;
1926             $$ = &freelist[fcnt++];
1927 	    copy_vrbl($$, $1);
1928             $$->type = GRARR_TMP;
1929 
1930 	    for (i = 0; i < $$->length; i++) {
1931 		$$->data[i] = ($1->data[i] != $3);
1932 	    }
1933 	}
1934 	| expr NE vexpr
1935 	{
1936 	    int i;
1937             $$ = &freelist[fcnt++];
1938 	    copy_vrbl($$, $3);
1939             $$->type = GRARR_TMP;
1940 
1941 	    for (i = 0; i < $$->length; i++) {
1942 		$$->data[i] = ($1 != $3->data[i]);
1943 	    }
1944 	}
1945 	| NOT vexpr
1946 	{
1947 	    int i;
1948             $$ = &freelist[fcnt++];
1949 	    copy_vrbl($$, $2);
1950             $$->type = GRARR_TMP;
1951             for (i = 0; i < $$->length; i++) {
1952                 $$->data[i] = !$2->data[i];
1953             }
1954 	}
1955 	| '(' vexpr ')'
1956 	{
1957 	    int i;
1958             $$ = &freelist[fcnt++];
1959 	    copy_vrbl($$, $2);
1960             $$->type = GRARR_TMP;
1961             for (i = 0; i < $$->length; i++) {
1962                 $$->data[i] = $2->data[i];
1963             }
1964 	}
1965 	| '-' vexpr %prec UMINUS {
1966 	    int i;
1967             $$ = &freelist[fcnt++];
1968 	    copy_vrbl($$, $2);
1969             $$->type = GRARR_TMP;
1970             for (i = 0; i < $$->length; i++) {
1971                 $$->data[i] = - $2->data[i];
1972             }
1973 	}
1974 	;
1975 
1976 
1977 asgn:
1978 	VAR_D '=' expr
1979 	{
1980 	    *($1) = $3;
1981 	}
1982 	| FITPARM '=' expr
1983 	{
1984 	    nonl_parms[$1].value = $3;
1985 	}
1986 	| FITPMAX '=' expr
1987 	{
1988 	    nonl_parms[$1].max = $3;
1989 	}
1990 	| FITPMIN '=' expr
1991 	{
1992 	    nonl_parms[$1].min = $3;
1993 	}
1994 	| array indx '=' expr
1995 	{
1996 	    if ($2 >= $1->length) {
1997 		yyerror("Access beyond array bounds");
1998 		return 1;
1999             }
2000             $1->data[$2] = $4;
2001 	}
2002 	;
2003 
2004 lside_array:
2005         array
2006         {
2007             target tgt;
2008             switch ($1->type) {
2009             case GRARR_SET:
2010                 if (find_set_bydata($1->data, &tgt) == RETURN_SUCCESS) {
2011                     vasgn_gno   = tgt.gno;
2012                     vasgn_setno = tgt.setno;
2013                 } else {
2014                     errmsg("Internal error");
2015 		    return 1;
2016                 }
2017                 break;
2018             case GRARR_VEC:
2019                 vasgn_gno   = -1;
2020                 vasgn_setno = -1;
2021                 break;
2022             default:
2023                 /* It can NOT be a tmp array on the left side! */
2024                 errmsg("Internal error");
2025 	        return 1;
2026             }
2027             $$ = $1;
2028         }
2029         ;
2030 
2031 vasgn:
2032 	lside_array '=' vexpr
2033 	{
2034 	    int i;
2035 	    if ($1->length != $3->length) {
2036                 errmsg("Left and right vectors are of different lengths");
2037                 return 1;
2038             }
2039 	    for (i = 0; i < $1->length; i++) {
2040 	        $1->data[i] = $3->data[i];
2041 	    }
2042 	}
2043 	| lside_array '=' expr
2044 	{
2045 	    int i;
2046 	    for (i = 0; i < $1->length; i++) {
2047 	        $1->data[i] = $3;
2048 	    }
2049 	}
2050         ;
2051 
2052 defines:
2053 	DEFINE NEW_TOKEN
2054         {
2055 	    symtab_entry tmpkey;
2056             double *var;
2057 
2058             var = xmalloc(SIZEOF_DOUBLE);
2059             *var = 0.0;
2060 
2061 	    tmpkey.s = $2;
2062 	    tmpkey.type = KEY_VAR;
2063 	    tmpkey.data = (void *) var;
2064 	    if (addto_symtab(tmpkey) != RETURN_SUCCESS) {
2065 	        yyerror("Adding new symbol failed");
2066 	    }
2067 
2068             xfree($2);
2069         }
2070 	| DEFINE NEW_TOKEN '[' ']'
2071         {
2072 	    if (define_parser_arr($2) == NULL) {
2073 	        yyerror("Adding new symbol failed");
2074 	    }
2075 
2076             xfree($2);
2077         }
2078 	| DEFINE NEW_TOKEN '[' nexpr ']'
2079         {
2080 	    grarr *var;
2081             if ((var = define_parser_arr($2)) == NULL) {
2082 	        yyerror("Adding new symbol failed");
2083 	    } else {
2084                 realloc_vrbl(var, $4);
2085             }
2086 
2087             xfree($2);
2088         }
2089 	| DEFINE VAR_D
2090         {
2091             yyerror("Keyword already exists");
2092         }
2093 	| DEFINE VEC_D
2094         {
2095             yyerror("Keyword already exists");
2096         }
2097 	| CLEAR VAR_D
2098         {
2099             undefine_parser_var((void *) $2);
2100             xfree($2);
2101         }
2102 	| CLEAR VEC_D
2103         {
2104             realloc_vrbl($2, 0);
2105             undefine_parser_var((void *) $2);
2106             xfree($2);
2107         }
2108 	| ALIAS sexpr sexpr {
2109 	    int position;
2110 
2111 	    lowtoupper($3);
2112 	    if ((position = findf(key, $3)) >= 0) {
2113 	        symtab_entry tmpkey;
2114 		tmpkey.s = $2;
2115 		tmpkey.type = key[position].type;
2116 		tmpkey.data = key[position].data;
2117 		if (addto_symtab(tmpkey) != RETURN_SUCCESS) {
2118 		    yyerror("Keyword already exists");
2119 		}
2120 	    } else {
2121 	        yyerror("Aliased keyword not found");
2122 	    }
2123 	    xfree($2);
2124 	    xfree($3);
2125 	}
2126 	| ALIAS FORCE onoff {
2127 	    alias_force = $3;
2128 	}
2129 	| USE sexpr TYPE proctype FROM sexpr {
2130 	    if (load_module($6, $2, $2, $4) != 0) {
2131 	        yyerror("DL module load failed");
2132 	    }
2133 	    xfree($2);
2134 	    xfree($6);
2135 	}
2136 	| USE sexpr TYPE proctype FROM sexpr ALIAS sexpr {
2137 	    if (load_module($6, $2, $8, $4) != 0) {
2138 	        yyerror("DL module load failed");
2139 	    }
2140 	    xfree($2);
2141 	    xfree($6);
2142 	    xfree($8);
2143 	}
2144         ;
2145 
2146 regionset:
2147 	REGNUM onoff {
2148 	    rg[$1].active = $2;
2149 	}
2150 	| REGNUM TYPE regiontype {
2151 	    rg[$1].type = $3;
2152 	}
2153 	| REGNUM color_select {
2154 	    rg[$1].color = $2;
2155 	}
2156 	| REGNUM lines_select {
2157 	    rg[$1].lines = $2;
2158 	}
2159 	| REGNUM linew_select {
2160 	    rg[$1].linew = $2;
2161 	}
2162 	| REGNUM LINE expr ',' expr ',' expr ',' expr
2163 	{
2164 	    rg[$1].x1 = $3;
2165 	    rg[$1].y1 = $5;
2166 	    rg[$1].x2 = $7;
2167 	    rg[$1].y2 = $9;
2168 	}
2169 	| REGNUM XY expr ',' expr
2170 	{
2171 	    rg[$1].x = xrealloc(rg[$1].x, (rg[$1].n + 1) * SIZEOF_DOUBLE);
2172 	    rg[$1].y = xrealloc(rg[$1].y, (rg[$1].n + 1) * SIZEOF_DOUBLE);
2173 	    rg[$1].x[rg[$1].n] = $3;
2174 	    rg[$1].y[rg[$1].n] = $5;
2175 	    rg[$1].n++;
2176 	}
2177 	| LINK REGNUM TO selectgraph {
2178 	    rg[$2].linkto = $4;
2179 	}
2180 	;
2181 
2182 
2183 parmset:
2184         VERSION nexpr {
2185             if (set_project_version($2) != RETURN_SUCCESS) {
2186                 errmsg("Project version is newer than software!");
2187             }
2188             if (get_project_version() < 50001) {
2189                 map_fonts(FONT_MAP_ACEGR);
2190             } else {
2191                 map_fonts(FONT_MAP_DEFAULT);
2192             }
2193         }
2194         | PAGE RESIZE nexpr ',' nexpr {
2195             set_page_dimensions($3, $5, TRUE);
2196         }
2197         | PAGE SIZE nexpr ',' nexpr {
2198             set_page_dimensions($3, $5, FALSE);
2199         }
2200 	| DEVICE sexpr PAGE SIZE nexpr ',' nexpr {
2201             int device_id;
2202             Device_entry dev;
2203 
2204             device_id = get_device_by_name($2);
2205             xfree($2);
2206             if (device_id < 0) {
2207                 yyerror("Unknown device");
2208             } else {
2209                 dev = get_device_props(device_id);
2210                 dev.pg.width =  (long) ($5*dev.pg.dpi/72);
2211                 dev.pg.height = (long) ($7*dev.pg.dpi/72);
2212                 set_device_props(device_id, dev);
2213             }
2214         }
2215         | DEVICE sexpr DPI expr {
2216             int device_id;
2217             Device_entry dev;
2218 
2219             device_id = get_device_by_name($2);
2220             if (device_id < 0) {
2221                 yyerror("Unknown device");
2222             } else {
2223                 dev = get_device_props(device_id);
2224                 dev.pg.dpi = $4;
2225                 set_device_props(device_id, dev);
2226             }
2227             xfree($2);
2228         }
2229         | DEVICE sexpr FONTP ANTIALIASING onoff {
2230             int device_id;
2231             Device_entry dev;
2232 
2233             device_id = get_device_by_name($2);
2234             if (device_id < 0) {
2235                 yyerror("Unknown device");
2236             } else {
2237                 dev = get_device_props(device_id);
2238                 dev.fontaa = $5;
2239                 set_device_props(device_id, dev);
2240             }
2241             xfree($2);
2242         }
2243         | DEVICE sexpr FONTP onoff {
2244             int device_id;
2245             Device_entry dev;
2246 
2247             device_id = get_device_by_name($2);
2248             if (device_id < 0) {
2249                 yyerror("Unknown device");
2250             } else {
2251                 dev = get_device_props(device_id);
2252                 dev.devfonts = $4;
2253                 set_device_props(device_id, dev);
2254             }
2255             xfree($2);
2256         }
2257         | DEVICE sexpr OP sexpr {
2258             int device_id;
2259 
2260             device_id = get_device_by_name($2);
2261             if (device_id < 0) {
2262                 yyerror("Unknown device");
2263             } else {
2264                 if (parse_device_options(device_id, $4) !=
2265                                                         RETURN_SUCCESS) {
2266                     yyerror("Incorrect device option string");
2267                 }
2268             }
2269             xfree($2);
2270             xfree($4);
2271         }
2272         | HARDCOPY DEVICE sexpr {
2273             set_printer_by_name($3);
2274             xfree($3);
2275         }
2276         | REFERENCE DATE jrawdate {
2277             set_ref_date($3);
2278 	}
2279         | DATE WRAP onoff {
2280             allow_two_digits_years($3);
2281 	}
2282         | DATE WRAP YEAR iexpr {
2283             set_wrap_year($4);
2284 	}
2285 	| BACKGROUND color_select {
2286 	    setbgcolor($2);
2287 	}
2288 	| PAGE BACKGROUND FILL onoff {
2289 	    setbgfill($4);
2290 	}
2291 	| PAGE SCROLL expr '%' {
2292 	    scroll_proc((int) $3);
2293 	}
2294 	| PAGE INOUT expr '%' {
2295 	    scrollinout_proc((int) $3);
2296 	}
2297 	| LINK PAGE onoff {
2298 	    scrolling_islinked = $3;
2299 	}
2300 
2301 	| STACK WORLD expr ',' expr ',' expr ',' expr
2302 	{
2303 	    add_world(whichgraph, $3, $5, $7, $9);
2304 	}
2305 
2306 	| TIMER nexpr {
2307             timer_delay = $2;
2308 	}
2309 
2310 	| TARGET selectset {
2311 	    target_set = *($2);
2312 	    set_parser_setno(target_set.gno, target_set.setno);
2313 	}
2314 	| WITH selectgraph {
2315 	    set_parser_gno($2);
2316 	}
2317 	| WITH selectset {
2318 	    set_parser_setno($2->gno, $2->setno);
2319 	}
2320 
2321 /* Hot links */
2322 	| selectset LINK sourcetype sexpr {
2323 	    set_hotlink($1->gno, $1->setno, 1, $4, $3);
2324 	    xfree($4);
2325 	}
2326 	| selectset LINK onoff {
2327 	    set_hotlink($1->gno, $1->setno, $3, NULL, 0);
2328 	}
2329 
2330 /* boxes */
2331 	| WITH BOX {
2332 	    curbox = next_box();
2333 	}
2334 	| WITH BOX nexpr {
2335             int no = $3;
2336             if (is_valid_box(no) ||
2337                 realloc_boxes(no + 1) == RETURN_SUCCESS) {
2338                 curbox = no;
2339             }
2340 	}
2341 	| BOX onoff {
2342 	    if (!is_valid_box(curbox)) {
2343                 yyerror("Box not active");
2344 	    } else {
2345 	        boxes[curbox].active = $2;
2346             }
2347 	}
2348 	| BOX selectgraph {
2349 	    if (!is_valid_box(curbox)) {
2350                 yyerror("Box not active");
2351 	    } else {
2352 	        boxes[curbox].gno = $2;
2353             }
2354 	}
2355 	| BOX expr ',' expr ',' expr ',' expr {
2356 	    if (!is_valid_box(curbox)) {
2357                 yyerror("Box not active");
2358 	    } else {
2359 		boxes[curbox].x1 = $2;
2360 		boxes[curbox].y1 = $4;
2361 		boxes[curbox].x2 = $6;
2362 		boxes[curbox].y2 = $8;
2363 	    }
2364 	}
2365 	| BOX LOCTYPE worldview {
2366 	    box_loctype = $3;
2367 	}
2368 	| BOX lines_select {
2369 	    box_lines = $2;
2370 	}
2371 	| BOX linew_select {
2372 	    box_linew = $2;
2373 	}
2374 	| BOX color_select {
2375 	    box_color = $2;
2376 	}
2377 	| BOX FILL color_select {
2378 	    box_fillcolor = $3;
2379 	}
2380 	| BOX FILL pattern_select {
2381 	    box_fillpat = $3;
2382 	}
2383 	| BOX DEF {
2384 	    if (!is_valid_box(curbox)) {
2385                 yyerror("Box not active");
2386 	    } else {
2387 		boxes[curbox].lines = box_lines;
2388 		boxes[curbox].linew = box_linew;
2389 		boxes[curbox].color = box_color;
2390 		if (get_project_version() <= 40102) {
2391                     switch (filltype_obs) {
2392                     case COLOR:
2393                         boxes[curbox].fillcolor = box_fillcolor;
2394 		        boxes[curbox].fillpattern = 1;
2395                         break;
2396                     case PATTERN:
2397                         boxes[curbox].fillcolor = 1;
2398 		        boxes[curbox].fillpattern = box_fillpat;
2399                         break;
2400                     default: /* NONE */
2401                         boxes[curbox].fillcolor = box_fillcolor;
2402 		        boxes[curbox].fillpattern = 0;
2403                         break;
2404                     }
2405 		} else {
2406                     boxes[curbox].fillcolor = box_fillcolor;
2407 		    boxes[curbox].fillpattern = box_fillpat;
2408                 }
2409                 boxes[curbox].loctype = box_loctype;
2410 	    }
2411 	}
2412 
2413 /* ellipses */
2414 	| WITH ELLIPSE {
2415 		curellipse = next_ellipse();
2416 	}
2417 	| WITH ELLIPSE nexpr {
2418             int no = $3;
2419             if (is_valid_ellipse(no) ||
2420                 realloc_ellipses(no + 1) == RETURN_SUCCESS) {
2421                 curellipse = no;
2422             }
2423 	}
2424 	| ELLIPSE onoff {
2425 	    if (!is_valid_ellipse(curellipse)) {
2426                 yyerror("Ellipse not active");
2427 	    } else {
2428 	        ellip[curellipse].active = $2;
2429             }
2430 	}
2431 	| ELLIPSE selectgraph {
2432 	    if (!is_valid_ellipse(curellipse)) {
2433                 yyerror("Ellipse not active");
2434 	    } else {
2435 	        ellip[curellipse].gno = $2;
2436             }
2437 	}
2438 	| ELLIPSE expr ',' expr ',' expr ',' expr {
2439 	    if (!is_valid_ellipse(curellipse)) {
2440                 yyerror("Ellipse not active");
2441 	    } else {
2442 		ellip[curellipse].x1 = $2;
2443 		ellip[curellipse].y1 = $4;
2444 		ellip[curellipse].x2 = $6;
2445 		ellip[curellipse].y2 = $8;
2446 	    }
2447 	}
2448 	| ELLIPSE LOCTYPE worldview {
2449 	    ellipse_loctype = $3;
2450 	}
2451 	| ELLIPSE lines_select {
2452 	    ellipse_lines = $2;
2453 	}
2454 	| ELLIPSE linew_select {
2455 	    ellipse_linew = $2;
2456 	}
2457 	| ELLIPSE color_select {
2458 	    ellipse_color = $2;
2459 	}
2460 	| ELLIPSE FILL color_select {
2461 	    ellipse_fillcolor = $3;
2462 	}
2463 	| ELLIPSE FILL pattern_select {
2464 	    ellipse_fillpat = $3;
2465 	}
2466 	| ELLIPSE DEF {
2467 	    if (!is_valid_ellipse(curellipse)) {
2468                 yyerror("Ellipse not active");
2469 	    } else {
2470 		ellip[curellipse].lines = ellipse_lines;
2471 		ellip[curellipse].linew = ellipse_linew;
2472 		ellip[curellipse].color = ellipse_color;
2473 		if (get_project_version() <= 40102) {
2474                     switch (filltype_obs) {
2475                     case COLOR:
2476                         ellip[curellipse].fillcolor = ellipse_fillcolor;
2477 		        ellip[curellipse].fillpattern = 1;
2478                         break;
2479                     case PATTERN:
2480                         ellip[curellipse].fillcolor = 1;
2481 		        ellip[curellipse].fillpattern = ellipse_fillpat;
2482                         break;
2483                     default: /* NONE */
2484                         ellip[curellipse].fillcolor = ellipse_fillcolor;
2485 		        ellip[curellipse].fillpattern = 0;
2486                         break;
2487                     }
2488 		} else {
2489                     ellip[curellipse].fillcolor = ellipse_fillcolor;
2490 		    ellip[curellipse].fillpattern = ellipse_fillpat;
2491                 }
2492 		ellip[curellipse].loctype = ellipse_loctype;
2493 	    }
2494 	}
2495 
2496 /* lines */
2497 	| WITH LINE {
2498 	    curline = next_line();
2499 	}
2500 	| WITH LINE nexpr {
2501             int no = $3;
2502             if (is_valid_line(no) ||
2503                 realloc_lines(no + 1) == RETURN_SUCCESS) {
2504                 curline = no;
2505             }
2506 	}
2507 	| LINE onoff {
2508 	    if (!is_valid_line(curline)) {
2509                 yyerror("Line not active");
2510 	    } else {
2511 	        lines[curline].active = $2;
2512             }
2513 	}
2514 	| LINE selectgraph {
2515 	    if (!is_valid_line(curline)) {
2516                 yyerror("Line not active");
2517 	    } else {
2518 	        lines[curline].gno = $2;
2519             }
2520 	}
2521 	| LINE expr ',' expr ',' expr ',' expr {
2522 	    if (!is_valid_line(curline)) {
2523                 yyerror("Line not active");
2524 	    } else {
2525 	        lines[curline].x1 = $2;
2526 	        lines[curline].y1 = $4;
2527 	        lines[curline].x2 = $6;
2528 	        lines[curline].y2 = $8;
2529             }
2530 	}
2531 	| LINE LOCTYPE worldview {
2532 	    line_loctype = $3;
2533 	}
2534 	| LINE linew_select {
2535 	    line_linew = $2;
2536 	}
2537 	| LINE lines_select {
2538 	    line_lines = $2;
2539 	}
2540 	| LINE color_select {
2541 	    line_color = $2;
2542 	}
2543 	| LINE ARROW nexpr {
2544 	    line_arrow_end = $3;
2545 	}
2546 	| LINE ARROW LENGTH expr {
2547 	    line_asize = $4;
2548 	}
2549 	| LINE ARROW TYPE nexpr {
2550 	    line_atype = $4;
2551 	}
2552 	| LINE ARROW LAYOUT expr ',' expr {
2553 	    line_a_dL_ff = $4;
2554 	    line_a_lL_ff = $6;
2555 	}
2556 	| LINE DEF {
2557 	    if (!is_valid_line(curline)) {
2558                 yyerror("Line not active");
2559 	    } else {
2560 	        lines[curline].lines = line_lines;
2561 	        lines[curline].linew = line_linew;
2562 	        lines[curline].color = line_color;
2563 	        lines[curline].arrow_end = line_arrow_end;
2564 	        lines[curline].arrow.length = line_asize;
2565 	        lines[curline].arrow.type = line_atype;
2566 	        lines[curline].arrow.dL_ff = line_a_dL_ff;
2567 	        lines[curline].arrow.lL_ff = line_a_lL_ff;
2568 	        lines[curline].loctype = line_loctype;
2569             }
2570 	}
2571 
2572 /* strings */
2573 	| WITH STRING {
2574             curstring = next_string();
2575         }
2576 	| WITH STRING nexpr {
2577             int no = $3;
2578             if (is_valid_string(no) ||
2579                 realloc_strings(no + 1) == RETURN_SUCCESS) {
2580                 curstring = no;
2581             }
2582         }
2583 	| STRING onoff {
2584 	    if (!is_valid_string(curstring)) {
2585                 yyerror("String not active");
2586 	    } else {
2587                 pstr[curstring].active = $2;
2588             }
2589         }
2590 	| STRING selectgraph {
2591 	    if (!is_valid_string(curstring)) {
2592                 yyerror("String not active");
2593 	    } else {
2594                 pstr[curstring].gno = $2;
2595             }
2596         }
2597 	| STRING expr ',' expr {
2598 	    if (!is_valid_string(curstring)) {
2599                 yyerror("String not active");
2600 	    } else {
2601 	        pstr[curstring].x = $2;
2602 	        pstr[curstring].y = $4;
2603             }
2604 	}
2605 	| STRING LOCTYPE worldview {
2606             string_loctype = $3;
2607         }
2608 	| STRING color_select {
2609             string_color = $2;
2610         }
2611 	| STRING ROT nexpr {
2612             string_rot = $3;
2613         }
2614 	| STRING font_select {
2615             string_font = $2;
2616         }
2617 	| STRING JUST nexpr {
2618             string_just = $3;
2619         }
2620 	| STRING CHAR SIZE expr {
2621             string_size = $4;
2622         }
2623 	| STRING DEF sexpr {
2624 	    if (!is_valid_string(curstring)) {
2625                 yyerror("String not active");
2626 	    } else {
2627 	        set_plotstr_string(&pstr[curstring], $3);
2628 	        pstr[curstring].color = string_color;
2629 	        pstr[curstring].font = string_font;
2630 	        pstr[curstring].just = string_just;
2631 	        pstr[curstring].loctype = string_loctype;
2632 	        pstr[curstring].rot = string_rot;
2633 	        pstr[curstring].charsize = string_size;
2634             }
2635 	    xfree($3);
2636 	}
2637 
2638 /* timestamp */
2639 	| TIMESTAMP onoff {
2640             timestamp.active = $2;
2641         }
2642 	| TIMESTAMP font_select {
2643             timestamp.font = $2;
2644         }
2645 	| TIMESTAMP CHAR SIZE expr {
2646             timestamp.charsize = $4;
2647         }
2648 	| TIMESTAMP ROT nexpr {
2649             timestamp.rot = $3;
2650         }
2651 	| TIMESTAMP color_select {
2652             timestamp.color = $2;
2653         }
2654 	| TIMESTAMP expr ',' expr {
2655 	    timestamp.x = $2;
2656 	    timestamp.y = $4;
2657 	}
2658 	| TIMESTAMP DEF sexpr {
2659 	  set_plotstr_string(&timestamp, $3);
2660 	  xfree($3);
2661 	}
2662 
2663 /* defaults */
2664 	| DEFAULT lines_select {
2665 	    grdefaults.lines = $2;
2666 	    box_lines = ellipse_lines = line_lines = $2;
2667 	}
2668 	| DEFAULT linew_select {
2669 	    grdefaults.linew = $2;
2670 	    box_linew = ellipse_linew = line_linew = $2;
2671 	}
2672 	| DEFAULT color_select {
2673 	    grdefaults.color = $2;
2674 	    box_color = ellipse_color = line_color = string_color = $2;
2675 	}
2676 	| DEFAULT pattern_select {
2677 	    grdefaults.pattern = $2;
2678 	}
2679 	| DEFAULT CHAR SIZE expr {
2680 	    grdefaults.charsize = $4;
2681 	    string_size = $4;
2682 	}
2683 	| DEFAULT font_select {
2684 	    grdefaults.font = $2;
2685 	    string_font = $2;
2686 	}
2687 	| DEFAULT SYMBOL SIZE expr {
2688 	    grdefaults.symsize = $4;
2689 	}
2690 	| DEFAULT SFORMAT sexpr {
2691 	    strcpy(sformat, $3);
2692 	    xfree($3);
2693 	}
2694 	| MAP FONTP nexpr TO sexpr ',' sexpr {
2695 	    if ((map_font_by_name($5, $3) != RETURN_SUCCESS) &&
2696                 (map_font_by_name($7, $3) != RETURN_SUCCESS)) {
2697                 errmsg("Failed mapping a font");
2698             }
2699             xfree($5);
2700 	    xfree($7);
2701 	}
2702 	| MAP COLOR nexpr TO '(' nexpr ',' nexpr ',' nexpr ')' ',' sexpr {
2703 	    CMap_entry cmap;
2704             cmap.rgb.red   = $6;
2705             cmap.rgb.green = $8;
2706             cmap.rgb.blue  = $10;
2707             cmap.ctype = COLOR_MAIN;
2708             cmap.cname = $13;
2709             if (store_color($3, cmap) == RETURN_FAILURE) {
2710                 errmsg("Failed mapping a color");
2711             }
2712 	    xfree($13);
2713         }
2714 
2715 	| WORLD expr ',' expr ',' expr ',' expr {
2716 	    if (!is_valid_gno(whichgraph)) {
2717                 yyerror("No valid graph selected");
2718                 return 1;
2719             }
2720 	    g[whichgraph].w.xg1 = $2;
2721 	    g[whichgraph].w.yg1 = $4;
2722 	    g[whichgraph].w.xg2 = $6;
2723 	    g[whichgraph].w.yg2 = $8;
2724 	}
2725 	| ZNORM expr {
2726 	    set_graph_znorm(whichgraph, $2);
2727 	}
2728 	| VIEW expr ',' expr ',' expr ',' expr {
2729 	    if (!is_valid_gno(whichgraph)) {
2730                 yyerror("No valid graph selected");
2731                 return 1;
2732             }
2733 	    g[whichgraph].v.xv1 = $2;
2734 	    g[whichgraph].v.yv1 = $4;
2735 	    g[whichgraph].v.xv2 = $6;
2736 	    g[whichgraph].v.yv2 = $8;
2737 	}
2738 	| TITLE sexpr {
2739 	    if (!is_valid_gno(whichgraph)) {
2740                 yyerror("No valid graph selected");
2741                 return 1;
2742             }
2743 	    set_plotstr_string(&g[whichgraph].labs.title, $2);
2744 	    xfree($2);
2745 	}
2746 	| TITLE font_select {
2747 	    if (!is_valid_gno(whichgraph)) {
2748                 yyerror("No valid graph selected");
2749                 return 1;
2750             }
2751 	    g[whichgraph].labs.title.font = $2;
2752 	}
2753 	| TITLE SIZE expr {
2754 	    if (!is_valid_gno(whichgraph)) {
2755                 yyerror("No valid graph selected");
2756                 return 1;
2757             }
2758 	    g[whichgraph].labs.title.charsize = $3;
2759 	}
2760 	| TITLE color_select {
2761 	    if (!is_valid_gno(whichgraph)) {
2762                 yyerror("No valid graph selected");
2763                 return 1;
2764             }
2765 	    g[whichgraph].labs.title.color = $2;
2766 	}
2767 	| SUBTITLE sexpr {
2768 	    if (!is_valid_gno(whichgraph)) {
2769                 yyerror("No valid graph selected");
2770                 return 1;
2771             }
2772 	    set_plotstr_string(&g[whichgraph].labs.stitle, $2);
2773 	    xfree($2);
2774 	}
2775 	| SUBTITLE font_select {
2776 	    if (!is_valid_gno(whichgraph)) {
2777                 yyerror("No valid graph selected");
2778                 return 1;
2779             }
2780 	    g[whichgraph].labs.stitle.font = $2;
2781 	}
2782 	| SUBTITLE SIZE expr {
2783 	    if (!is_valid_gno(whichgraph)) {
2784                 yyerror("No valid graph selected");
2785                 return 1;
2786             }
2787 	    g[whichgraph].labs.stitle.charsize = $3;
2788 	}
2789 	| SUBTITLE color_select {
2790 	    if (!is_valid_gno(whichgraph)) {
2791                 yyerror("No valid graph selected");
2792                 return 1;
2793             }
2794 	    g[whichgraph].labs.stitle.color = $2;
2795 	}
2796 
2797 	| XAXES SCALE scaletype {
2798 	    if (!is_valid_gno(whichgraph)) {
2799                 yyerror("No valid graph selected");
2800                 return 1;
2801             }
2802 	    g[whichgraph].xscale = $3;
2803 	}
2804 	| YAXES SCALE scaletype {
2805 	    if (!is_valid_gno(whichgraph)) {
2806                 yyerror("No valid graph selected");
2807                 return 1;
2808             }
2809 	    g[whichgraph].yscale = $3;
2810 	}
2811 	| XAXES INVERT onoff {
2812 	    if (!is_valid_gno(whichgraph)) {
2813                 yyerror("No valid graph selected");
2814                 return 1;
2815             }
2816 	    g[whichgraph].xinvert = $3;
2817 	}
2818 	| YAXES INVERT onoff {
2819 	    if (!is_valid_gno(whichgraph)) {
2820                 yyerror("No valid graph selected");
2821                 return 1;
2822             }
2823 	    g[whichgraph].yinvert = $3;
2824 	}
2825 	| AUTOSCALE ONREAD NONE {
2826             autoscale_onread = AUTOSCALE_NONE;
2827         }
2828 	| AUTOSCALE ONREAD XAXES {
2829             autoscale_onread = AUTOSCALE_X;
2830         }
2831 	| AUTOSCALE ONREAD YAXES {
2832             autoscale_onread = AUTOSCALE_Y;
2833         }
2834 	| AUTOSCALE ONREAD XYAXES {
2835             autoscale_onread = AUTOSCALE_XY;
2836         }
2837 
2838 	| DESCRIPTION sexpr {
2839             char *s;
2840             s = copy_string(NULL, get_project_description());
2841             s = concat_strings(s, $2);
2842 	    xfree($2);
2843             s = concat_strings(s, "\n");
2844             set_project_description(s);
2845             xfree(s);
2846 	}
2847         | CLEAR DESCRIPTION {
2848             set_project_description(NULL);
2849         }
2850 
2851 	| LEGEND onoff {
2852 	    if (!is_valid_gno(whichgraph)) {
2853                 yyerror("No valid graph selected");
2854                 return 1;
2855             }
2856 	    g[whichgraph].l.active = $2;
2857 	}
2858 	| LEGEND LOCTYPE worldview {
2859 	    if (!is_valid_gno(whichgraph)) {
2860                 yyerror("No valid graph selected");
2861                 return 1;
2862             }
2863 	    g[whichgraph].l.loctype = $3;
2864 	}
2865 	| LEGEND VGAP nexpr {
2866 	    if (!is_valid_gno(whichgraph)) {
2867                 yyerror("No valid graph selected");
2868                 return 1;
2869             }
2870             g[whichgraph].l.vgap = $3;
2871 	}
2872 	| LEGEND HGAP nexpr {
2873 	    if (!is_valid_gno(whichgraph)) {
2874                 yyerror("No valid graph selected");
2875                 return 1;
2876             }
2877 	    g[whichgraph].l.hgap = $3;
2878 	}
2879 	| LEGEND LENGTH nexpr {
2880 	    if (!is_valid_gno(whichgraph)) {
2881                 yyerror("No valid graph selected");
2882                 return 1;
2883             }
2884 	    g[whichgraph].l.len = $3;
2885 	}
2886 	| LEGEND INVERT onoff {
2887 	    if (!is_valid_gno(whichgraph)) {
2888                 yyerror("No valid graph selected");
2889                 return 1;
2890             }
2891 	    g[whichgraph].l.invert = $3;
2892         }
2893 	| LEGEND BOX FILL color_select {
2894 	    if (!is_valid_gno(whichgraph)) {
2895                 yyerror("No valid graph selected");
2896                 return 1;
2897             }
2898 	    g[whichgraph].l.boxfillpen.color = $4;
2899         }
2900 	| LEGEND BOX FILL pattern_select {
2901 	    if (!is_valid_gno(whichgraph)) {
2902                 yyerror("No valid graph selected");
2903                 return 1;
2904             }
2905 	    g[whichgraph].l.boxfillpen.pattern = $4;
2906         }
2907 	| LEGEND BOX color_select {
2908 	    if (!is_valid_gno(whichgraph)) {
2909                 yyerror("No valid graph selected");
2910                 return 1;
2911             }
2912 	    g[whichgraph].l.boxpen.color = $3;
2913 	}
2914 	| LEGEND BOX pattern_select {
2915 	    if (!is_valid_gno(whichgraph)) {
2916                 yyerror("No valid graph selected");
2917                 return 1;
2918             }
2919 	    g[whichgraph].l.boxpen.pattern = $3;
2920 	}
2921 	| LEGEND BOX lines_select {
2922 	    if (!is_valid_gno(whichgraph)) {
2923                 yyerror("No valid graph selected");
2924                 return 1;
2925             }
2926 	    g[whichgraph].l.boxlines = $3;
2927 	}
2928 	| LEGEND BOX linew_select {
2929 	    if (!is_valid_gno(whichgraph)) {
2930                 yyerror("No valid graph selected");
2931                 return 1;
2932             }
2933 	    g[whichgraph].l.boxlinew = $3;
2934 	}
2935 	| LEGEND expr ',' expr {
2936 	    if (!is_valid_gno(whichgraph)) {
2937                 yyerror("No valid graph selected");
2938                 return 1;
2939             }
2940 	    g[whichgraph].l.legx = $2;
2941 	    g[whichgraph].l.legy = $4;
2942 	}
2943 	| LEGEND CHAR SIZE expr {
2944 	    if (!is_valid_gno(whichgraph)) {
2945                 yyerror("No valid graph selected");
2946                 return 1;
2947             }
2948 	    g[whichgraph].l.charsize = $4;
2949 	}
2950 	| LEGEND font_select {
2951 	    if (!is_valid_gno(whichgraph)) {
2952                 yyerror("No valid graph selected");
2953                 return 1;
2954             }
2955 	    g[whichgraph].l.font = $2;
2956 	}
2957 	| LEGEND color_select {
2958 	    if (!is_valid_gno(whichgraph)) {
2959                 yyerror("No valid graph selected");
2960                 return 1;
2961             }
2962 	    g[whichgraph].l.color = $2;
2963 	}
2964 
2965 	| FRAMEP onoff {
2966 	    if (!is_valid_gno(whichgraph)) {
2967                 yyerror("No valid graph selected");
2968                 return 1;
2969             }
2970             g[whichgraph].f.pen.pattern = $2;
2971 	}
2972 	| FRAMEP TYPE nexpr {
2973 	    if (!is_valid_gno(whichgraph)) {
2974                 yyerror("No valid graph selected");
2975                 return 1;
2976             }
2977 	    g[whichgraph].f.type = $3;
2978 	}
2979 	| FRAMEP lines_select {
2980 	    if (!is_valid_gno(whichgraph)) {
2981                 yyerror("No valid graph selected");
2982                 return 1;
2983             }
2984 	    g[whichgraph].f.lines = $2;
2985 	}
2986 	| FRAMEP linew_select {
2987 	    if (!is_valid_gno(whichgraph)) {
2988                 yyerror("No valid graph selected");
2989                 return 1;
2990             }
2991 	    g[whichgraph].f.linew = $2;
2992 	}
2993 	| FRAMEP color_select {
2994 	    if (!is_valid_gno(whichgraph)) {
2995                 yyerror("No valid graph selected");
2996                 return 1;
2997             }
2998 	    g[whichgraph].f.pen.color = $2;
2999 	}
3000 	| FRAMEP pattern_select {
3001 	    if (!is_valid_gno(whichgraph)) {
3002                 yyerror("No valid graph selected");
3003                 return 1;
3004             }
3005 	    g[whichgraph].f.pen.pattern = $2;
3006 	}
3007 	| FRAMEP BACKGROUND color_select
3008         {
3009 	    if (!is_valid_gno(whichgraph)) {
3010                 yyerror("No valid graph selected");
3011                 return 1;
3012             }
3013             g[whichgraph].f.fillpen.color = $3;
3014         }
3015 	| FRAMEP BACKGROUND pattern_select
3016         {
3017 	    if (!is_valid_gno(whichgraph)) {
3018                 yyerror("No valid graph selected");
3019                 return 1;
3020             }
3021             g[whichgraph].f.fillpen.pattern = $3;
3022         }
3023 
3024 	| selectgraph onoff {
3025             set_graph_hidden($1, !$2);
3026         }
3027 	| selectgraph HIDDEN onoff {
3028             set_graph_hidden($1, $3);
3029         }
3030 	| selectgraph TYPE graphtype {
3031             set_graph_type($1, $3);
3032         }
3033 	| selectgraph STACKED onoff {
3034             set_graph_stacked($1, $3);
3035         }
3036 
3037 	| selectgraph BAR HGAP expr {
3038 	    set_graph_bargap($1, $4);
3039 	}
3040 
3041 	| selectgraph FIXEDPOINT onoff {
3042             g[$1].locator.pointset = $3;
3043         }
3044 	| selectgraph FIXEDPOINT FORMAT formatchoice formatchoice {
3045 	    g[$1].locator.fx = $4;
3046 	    g[$1].locator.fy = $5;
3047 	}
3048 	| selectgraph FIXEDPOINT PREC expr ',' expr {
3049 	    g[$1].locator.px = $4;
3050 	    g[$1].locator.py = $6;
3051 	}
3052 	| selectgraph FIXEDPOINT XY expr ',' expr {
3053 	    g[$1].locator.dsx = $4;
3054 	    g[$1].locator.dsy = $6;
3055 	}
3056 	| selectgraph FIXEDPOINT TYPE nexpr {
3057             g[$1].locator.pt_type = $4;
3058         }
3059 
3060 	| TYPE xytype {
3061 	    curtype = $2;
3062 	}
3063 
3064 /* I/O filters */
3065 	| DEFINE filtertype sexpr filtermethod sexpr {
3066 	    if (add_io_filter($2, $4, $5, $3) != 0) {
3067 	        yyerror("Failed adding i/o filter");
3068 	    }
3069 	    xfree($3);
3070 	    xfree($5);
3071 	}
3072 	| CLEAR filtertype {
3073 	    clear_io_filters($2);
3074 	}
3075 
3076 	| SOURCE sourcetype {
3077 	    cursource = $2;
3078 	}
3079 	| FORMAT formatchoice {
3080 	    readxformat = $2;
3081 	}
3082         | FIT nonlfitopts { }
3083 	| FITPARM CONSTRAINTS onoff {
3084 	    nonl_parms[$1].constr = $3;
3085 	}
3086 	;
3087 
3088 actions:
3089 	REDRAW {
3090 	    drawgraph();
3091 	}
3092 	| UPDATEALL {
3093 #ifndef NONE_GUI
3094             if (inwin) {
3095                 update_all();
3096             }
3097 #endif
3098         }
3099 	| CD sexpr {
3100 	    set_workingdir($2);
3101 	    xfree($2);
3102 	}
3103 	| ECHO sexpr {
3104 	    echomsg($2);
3105 	    xfree($2);
3106 	}
3107 	| ECHO expr {
3108 	    char buf[32];
3109             set_locale_num(TRUE);
3110             sprintf(buf, "%g", $2);
3111             set_locale_num(FALSE);
3112             echomsg(buf);
3113 	}
3114 	| CLOSE {
3115 	    close_input = copy_string(close_input, "");
3116 	}
3117 	| CLOSE sexpr {
3118 	    close_input = copy_string(close_input, $2);
3119 	}
3120 	| EXIT {
3121 	    exit(0);
3122 	}
3123 	| EXIT '(' iexpr ')' {
3124 	    exit($3);
3125 	}
3126 	| PRINT {
3127 	    if (!safe_mode) {
3128                 do_hardcopy();
3129             } else {
3130                 yyerror("File modifications are disabled in safe mode");
3131             }
3132 	}
3133 	| PRINT TO DEVICE {
3134             set_ptofile(FALSE);
3135 	}
3136 	| PRINT TO sexpr {
3137             set_ptofile(TRUE);
3138 	    strcpy(print_file, $3);
3139             xfree($3);
3140 	}
3141 	| PAGE direction {
3142 	    switch ($2) {
3143 	    case UP:
3144 		graph_scroll(GSCROLL_UP);
3145 		break;
3146 	    case DOWN:
3147 		graph_scroll(GSCROLL_DOWN);
3148 		break;
3149 	    case RIGHT:
3150 		graph_scroll(GSCROLL_RIGHT);
3151 		break;
3152 	    case LEFT:
3153 		graph_scroll(GSCROLL_LEFT);
3154 		break;
3155 	    case IN:
3156 		graph_zoom(GZOOM_SHRINK);
3157 		break;
3158 	    case OUT:
3159 		graph_zoom(GZOOM_EXPAND);
3160 		break;
3161 	    }
3162 	}
3163 	| SLEEP expr {
3164 	    if ($2 > 0) {
3165 	        msleep_wrap((unsigned int) (1000 * $2));
3166 	    }
3167 	}
3168 	| HELP sexpr {
3169 #ifndef NONE_GUI
3170             if (inwin) {
3171                 HelpCB($2);
3172             }
3173             xfree($2);
3174 #endif
3175 	}
3176 	| HELP {
3177 #ifndef NONE_GUI
3178             if (inwin) {
3179                 HelpCB("doc/UsersGuide.html");
3180             }
3181 #endif
3182 	}
3183 	| GETP sexpr {
3184 	    gotparams = TRUE;
3185 	    strcpy(paramfile, $2);
3186 	    xfree($2);
3187 	}
3188 	| PUTP sexpr {
3189 	    if (!safe_mode) {
3190                 FILE *pp = grace_openw($2);
3191 	        if (pp != NULL) {
3192 	            putparms(whichgraph, pp, 0);
3193 	            grace_close(pp);
3194 	        }
3195             } else {
3196                 yyerror("File modifications are disabled in safe mode");
3197             }
3198 	    xfree($2);
3199 	}
3200 	| selectset HIDDEN onoff {
3201 	    set_set_hidden($1->gno, $1->setno, $3);
3202 	}
3203 	| selectset LENGTH nexpr {
3204 	    setlength($1->gno, $1->setno, $3);
3205 	}
3206 	| VEC_D LENGTH nexpr {
3207 	    realloc_vrbl($1, $3);
3208 	}
3209 	| selectset POINT expr ',' expr {
3210 	    add_point($1->gno, $1->setno, $3, $5);
3211 	}
3212 
3213 	| selectset DROP nexpr ',' nexpr {
3214 	    int start = $3 - index_shift;
3215 	    int stop = $5 - index_shift;
3216 	    droppoints($1->gno, $1->setno, start, stop);
3217 	}
3218 	| SORT selectset sorton sortdir {
3219 	    if (is_set_active($2->gno, $2->setno)) {
3220 	        sortset($2->gno, $2->setno, $3, $4 == ASCENDING ? 0 : 1);
3221 	    }
3222 	}
3223 	| COPY selectset TO selectset {
3224 	    do_copyset($2->gno, $2->setno, $4->gno, $4->setno);
3225 	}
3226 	| APPEND selectset TO selectset {
3227 	    if ($2->gno != $4->gno) {
3228                 errmsg("Can't append sets from different graphs");
3229             } else {
3230                 int sets[2];
3231 	        sets[0] = $4->setno;
3232 	        sets[1] = $2->setno;
3233 	        join_sets($2->gno, sets, 2);
3234             }
3235 	}
3236 	| REVERSE selectset {
3237             reverse_set($2->gno, $2->setno);
3238 	}
3239 	| SPLIT selectset nexpr {
3240             do_splitsets($2->gno, $2->setno, $3);
3241 	}
3242 	| MOVE selectset TO selectset {
3243 	    do_moveset($2->gno, $2->setno, $4->gno, $4->setno);
3244 	}
3245 	| SWAP selectset AND selectset {
3246 	    do_swapset($2->gno, $2->setno, $4->gno, $4->setno);
3247 	}
3248 	| KILL selectset {
3249 	    killset($2->gno, $2->setno);
3250 	}
3251 	| KILL selectset SAVEALL {
3252             killsetdata($2->gno, $2->setno);
3253             setcomment($2->gno, $2->setno, "");
3254         }
3255 	| KILL selectgraph {
3256             kill_graph($2);
3257         }
3258 	| KILL REGNUM {
3259             kill_region($2);
3260         }
3261 	| FLUSH {
3262             wipeout();
3263         }
3264 	| ARRANGE '(' nexpr ',' nexpr ',' expr ',' expr ',' expr ')' {
3265             arrange_graphs_simple($3, $5, 0, FALSE, $7, $9, $11);
3266         }
3267 	| ARRANGE '(' nexpr ',' nexpr ',' expr ',' expr ',' expr ',' onoff ',' onoff ',' onoff ')' {
3268             int order = ($13 * GA_ORDER_HV_INV) |
3269                         ($15 * GA_ORDER_H_INV ) |
3270                         ($17 * GA_ORDER_V_INV );
3271             arrange_graphs_simple($3, $5, order, FALSE, $7, $9, $11);
3272         }
3273 	| ARRANGE '(' nexpr ',' nexpr ',' expr ',' expr ',' expr ',' onoff ',' onoff ',' onoff ',' onoff ')' {
3274             int order = ($13 * GA_ORDER_HV_INV) |
3275                         ($15 * GA_ORDER_H_INV ) |
3276                         ($17 * GA_ORDER_V_INV );
3277             arrange_graphs_simple($3, $5, order, $19, $7, $9, $11);
3278         }
3279 	| NONLFIT '(' selectset ',' nexpr ')' {
3280 	    gotnlfit = TRUE;
3281 	    nlfit_gno = $3->gno;
3282 	    nlfit_setno = $3->setno;
3283 	    nlfit_nsteps = $5;
3284 	    nlfit_warray = NULL;
3285 	}
3286 	| NONLFIT '(' selectset ',' vexpr ',' nexpr ')' {
3287 	    if (getsetlength($3->gno, $3->setno) != $5->length) {
3288                 errmsg("Data and weight arrays are of different lengths");
3289                 return 1;
3290             } else {
3291 	        gotnlfit = TRUE;
3292 	        nlfit_gno = $3->gno;
3293 	        nlfit_setno = $3->setno;
3294 	        nlfit_nsteps = $7;
3295 	        nlfit_warray = copy_data_column($5->data, $5->length);
3296             }
3297 	}
3298 	| REGRESS '(' selectset ',' nexpr ')' {
3299 	    do_regress($3->gno, $3->setno, $5, 0, -1, 0, -1);
3300 	}
3301 	| runtype '(' selectset ',' nexpr ')' {
3302 	    do_runavg($3->gno, $3->setno, $5, $1, -1, 0);
3303 	}
3304 	| ffttype '(' selectset ',' nexpr ')' {
3305 	    do_fourier_command($3->gno, $3->setno, $1, $5);
3306 	}
3307         | ffttype '(' selectset ',' fourierdata ',' windowtype ','
3308                       fourierloadx ','  fourierloady ')' {
3309 	    switch ($1) {
3310 	    case FFT_DFT:
3311                 do_fourier($3->gno, $3->setno, 0, $11, $9, 0, $5, $7);
3312 	        break;
3313 	    case FFT_INVDFT    :
3314                 do_fourier($3->gno, $3->setno, 0, $11, $9, 1, $5, $7);
3315 	        break;
3316 	    case FFT_FFT:
3317                 do_fourier($3->gno, $3->setno, 1, $11, $9, 0, $5, $7);
3318 	        break;
3319 	    case FFT_INVFFT    :
3320                 do_fourier($3->gno, $3->setno, 1, $11, $9, 1, $5, $7);
3321 	        break;
3322 	    default:
3323                 errmsg("Internal error");
3324 	        break;
3325 	    }
3326         }
3327 	| INTERPOLATE '(' selectset ',' vexpr ',' interpmethod ',' onoff ')' {
3328             do_interp($3->gno, $3->setno, get_cg(), SET_SELECT_NEXT,
3329                 $5->data, $5->length, $7, $9);
3330 	}
3331 	| HISTOGRAM '(' selectset ',' vexpr ',' onoff ',' onoff ')' {
3332             do_histo($3->gno, $3->setno, get_cg(), SET_SELECT_NEXT,
3333                 $5->data, $5->length - 1, $7, $9);
3334 	}
3335 	| DIFFERENCE '(' selectset ',' nexpr ')' {
3336 	    do_differ($3->gno, $3->setno, $5);
3337 	}
3338 	| INTEGRATE '(' selectset ')' {
3339 	    do_int($3->gno, $3->setno, 0);
3340 	}
3341  	| XCOR '(' selectset ',' selectset ',' nexpr ',' onoff ')' {
3342 	    do_xcor($3->gno, $3->setno, $5->gno, $5->setno, $7, $9);
3343 	}
3344  	| LINCONV '(' selectset ',' selectset ')' {
3345 	    do_linearc($3->gno, $3->setno, $5->gno, $5->setno);
3346 	}
3347  	| RESTRICT '(' selectset ',' vexpr ')' {
3348             int len = getsetlength($3->gno, $3->setno);
3349             if (len != $5->length) {
3350 		errmsg("Filter expression is of a wrong length");
3351             } else {
3352                 char *rarray;
3353                 rarray = xmalloc(len*SIZEOF_CHAR);
3354                 if (rarray) {
3355                     int i;
3356                     for (i = 0; i < len; i++) {
3357                         rarray[i] = CAST_DBL_TO_BOOL($5->data[i]);
3358                     }
3359                     filter_set($3->gno, $3->setno, rarray);
3360                     xfree(rarray);
3361                 }
3362             }
3363 	}
3364  	| RESTRICT '(' selectset ',' REGNUM ',' onoff ')' {
3365             int rtype;
3366             char *rarray;
3367 
3368             rtype = RESTRICT_REG0 + $5;
3369 
3370 	    if (get_restriction_array($3->gno, $3->setno,
3371                 rtype, $7, &rarray) != RETURN_SUCCESS) {
3372                 errmsg("Error in region evaluation");
3373                 return 1;
3374 	    } else {
3375                 filter_set($3->gno, $3->setno, rarray);
3376                 xfree(rarray);
3377             }
3378 	}
3379 	| AUTOSCALE {
3380 	    if (autoscale_graph(whichgraph, AUTOSCALE_XY) != RETURN_SUCCESS) {
3381 		errmsg("Can't autoscale (no active sets?)");
3382 	    }
3383 	}
3384 	| AUTOSCALE XAXES {
3385 	    if (autoscale_graph(whichgraph, AUTOSCALE_X) != RETURN_SUCCESS) {
3386 		errmsg("Can't autoscale (no active sets?)");
3387 	    }
3388 	}
3389 	| AUTOSCALE YAXES {
3390 	    if (autoscale_graph(whichgraph, AUTOSCALE_Y) != RETURN_SUCCESS) {
3391 		errmsg("Can't autoscale (no active sets?)");
3392 	    }
3393 	}
3394 	| AUTOSCALE selectset {
3395 	    autoscale_byset($2->gno, $2->setno, AUTOSCALE_XY);
3396 	}
3397         | AUTOTICKS {
3398             autotick_axis(whichgraph, ALL_AXES);
3399         }
3400 	| FOCUS selectgraph {
3401 	    int gno = $2;
3402             if (is_graph_hidden(gno) == FALSE) {
3403                 select_graph(gno);
3404             } else {
3405 		errmsg("Graph is not active");
3406             }
3407 	}
3408 	| READ sexpr {
3409 	    gotread = TRUE;
3410 	    strcpy(readfile, $2);
3411 	    xfree($2);
3412 	}
3413 	| READ BATCH sexpr {
3414 	    strcpy(batchfile, $3);
3415 	    xfree($3);
3416 	}
3417 	| READ BLOCK sexpr {
3418 	    getdata(whichgraph, $3, SOURCE_DISK, LOAD_BLOCK);
3419 	    xfree($3);
3420 	}
3421 	| READ BLOCK sourcetype sexpr {
3422 	    getdata(whichgraph, $4, $3, LOAD_BLOCK);
3423 	    xfree($4);
3424 	}
3425 	| BLOCK xytype sexpr {
3426             int nc, *cols, scol;
3427             if (field_string_to_cols($3, &nc, &cols, &scol) != RETURN_SUCCESS) {
3428                 errmsg("Erroneous field specifications");
3429 	        xfree($3);
3430                 return 1;
3431             } else {
3432 	        xfree($3);
3433 	        create_set_fromblock(whichgraph, NEW_SET,
3434                     $2, nc, cols, scol, autoscale_onread);
3435                 xfree(cols);
3436             }
3437 	}
3438 	| KILL BLOCK {
3439 	    set_blockdata(NULL);
3440 	}
3441 	| READ xytype sexpr {
3442 	    gotread = TRUE;
3443 	    curtype = $2;
3444 	    strcpy(readfile, $3);
3445 	    xfree($3);
3446 	}
3447 	| READ xytype sourcetype sexpr {
3448 	    gotread = TRUE;
3449 	    strcpy(readfile, $4);
3450 	    curtype = $2;
3451 	    cursource = $3;
3452 	    xfree($4);
3453 	}
3454 	| READ NXY sexpr {
3455 	    getdata(whichgraph, $3, SOURCE_DISK, LOAD_NXY);
3456 	    xfree($3);
3457 	}
3458 	| READ NXY sourcetype sexpr {
3459 	    getdata(whichgraph, $4, $3, LOAD_NXY);
3460 	    xfree($4);
3461 	}
3462 	| WRITE selectset {
3463 	    if (!safe_mode) {
3464                 outputset($2->gno, $2->setno, "stdout", NULL);
3465             } else {
3466                 yyerror("File modifications are disabled in safe mode");
3467             }
3468 	}
3469 	| WRITE selectset FORMAT sexpr {
3470 	    if (!safe_mode) {
3471 	        outputset($2->gno, $2->setno, "stdout", $4);
3472             } else {
3473                 yyerror("File modifications are disabled in safe mode");
3474             }
3475 	    xfree($4);
3476 	}
3477 	| WRITE selectset FILEP sexpr {
3478 	    if (!safe_mode) {
3479 	        outputset($2->gno, $2->setno, $4, NULL);
3480             } else {
3481                 yyerror("File modifications are disabled in safe mode");
3482             }
3483 	    xfree($4);
3484 	}
3485 	| WRITE selectset FILEP sexpr FORMAT sexpr {
3486 	    if (!safe_mode) {
3487 	        outputset($2->gno, $2->setno, $4, $6);
3488             } else {
3489                 yyerror("File modifications are disabled in safe mode");
3490             }
3491 	    xfree($4);
3492 	    xfree($6);
3493 	}
3494         | SAVEALL sexpr {
3495             if (!safe_mode) {
3496                 save_project($2);
3497             } else {
3498                 yyerror("File modifications are disabled in safe mode");
3499             }
3500             xfree($2);
3501         }
3502         | LOAD sexpr {
3503             load_project($2);
3504             xfree($2);
3505         }
3506         | NEW {
3507             new_project(NULL);
3508         }
3509         | NEW FROM sexpr {
3510             new_project($3);
3511             xfree($3);
3512         }
3513 	| PUSH {
3514 	    push_world();
3515 	}
3516 	| POP {
3517 	    pop_world();
3518 	}
3519 	| CYCLE {
3520 	    cycle_world_stack();
3521 	}
3522 	| STACK nexpr {
3523 	    if ($2 > 0)
3524 		show_world_stack($2 - 1);
3525 	}
3526 	| CLEAR STACK {
3527 	    clear_world_stack();
3528 	}
3529 	| CLEAR BOX {
3530 	    do_clear_boxes();
3531 	}
3532 	| CLEAR ELLIPSE {
3533 	    do_clear_ellipses();
3534 	}
3535 	| CLEAR LINE {
3536 	    do_clear_lines();
3537 	}
3538 	| CLEAR STRING {
3539 	    do_clear_text();
3540 	}
3541         ;
3542 
3543 
3544 options:
3545         PAGE LAYOUT pagelayout {
3546 #ifndef NONE_GUI
3547             set_pagelayout($3);
3548 #endif
3549         }
3550 	| AUTO REDRAW onoff {
3551 	    auto_redraw = $3;
3552 	}
3553 	| FOCUS onoff {
3554 	    draw_focus_flag = $2;
3555 	}
3556 	| FOCUS SET {
3557 	    focus_policy = FOCUS_SET;
3558 	}
3559 	| FOCUS FOLLOWS {
3560 	    focus_policy = FOCUS_FOLLOWS;
3561 	}
3562 	| FOCUS CLICK {
3563 	    focus_policy = FOCUS_CLICK;
3564 	}
3565         ;
3566 
3567 
3568 set_setprop:
3569 	setprop {}
3570 	| setprop_obs {}
3571 	;
3572 
3573 setprop:
3574 	selectset onoff {
3575 	    set_set_hidden($1->gno, $1->setno, !$2);
3576 	}
3577 	| selectset TYPE xytype {
3578 	    set_dataset_type($1->gno, $1->setno, $3);
3579 	}
3580 
3581 	| selectset SYMBOL nexpr {
3582 	    g[$1->gno].p[$1->setno].sym = $3;
3583 	}
3584 	| selectset SYMBOL color_select {
3585 	    g[$1->gno].p[$1->setno].sympen.color = $3;
3586 	}
3587 	| selectset SYMBOL pattern_select {
3588 	    g[$1->gno].p[$1->setno].sympen.pattern = $3;
3589 	}
3590 	| selectset SYMBOL linew_select {
3591 	    g[$1->gno].p[$1->setno].symlinew = $3;
3592 	}
3593 	| selectset SYMBOL lines_select {
3594 	    g[$1->gno].p[$1->setno].symlines = $3;
3595 	}
3596 	| selectset SYMBOL FILL color_select {
3597 	    g[$1->gno].p[$1->setno].symfillpen.color = $4;
3598 	}
3599 	| selectset SYMBOL FILL pattern_select {
3600 	    g[$1->gno].p[$1->setno].symfillpen.pattern = $4;
3601 	}
3602 	| selectset SYMBOL SIZE expr {
3603 	    g[$1->gno].p[$1->setno].symsize = $4;
3604 	}
3605 	| selectset SYMBOL CHAR nexpr {
3606 	    g[$1->gno].p[$1->setno].symchar = $4;
3607 	}
3608 	| selectset SYMBOL CHAR font_select {
3609 	    g[$1->gno].p[$1->setno].charfont = $4;
3610 	}
3611 	| selectset SYMBOL SKIP nexpr {
3612 	    g[$1->gno].p[$1->setno].symskip = $4;
3613 	}
3614 
3615 	| selectset LINE TYPE nexpr
3616         {
3617 	    g[$1->gno].p[$1->setno].linet = $4;
3618 	}
3619 	| selectset LINE lines_select
3620         {
3621 	    g[$1->gno].p[$1->setno].lines = $3;
3622 	}
3623 	| selectset LINE linew_select
3624         {
3625 	    g[$1->gno].p[$1->setno].linew = $3;
3626 	}
3627 	| selectset LINE color_select
3628         {
3629 	    g[$1->gno].p[$1->setno].linepen.color = $3;
3630 	}
3631 	| selectset LINE pattern_select
3632         {
3633 	    g[$1->gno].p[$1->setno].linepen.pattern = $3;
3634 	}
3635 
3636 	| selectset FILL TYPE nexpr
3637         {
3638 	    g[$1->gno].p[$1->setno].filltype = $4;
3639 	}
3640 	| selectset FILL RULE nexpr
3641         {
3642 	    g[$1->gno].p[$1->setno].fillrule = $4;
3643 	}
3644 	| selectset FILL color_select
3645         {
3646 	    int prop = $3;
3647 
3648 	    if (get_project_version() <= 40102 && get_project_version() >= 30000) {
3649                 switch (filltype_obs) {
3650                 case COLOR:
3651                     break;
3652                 case PATTERN:
3653                     prop = 1;
3654                     break;
3655                 default: /* NONE */
3656 	            prop = 0;
3657                     break;
3658                 }
3659 	    }
3660 	    g[$1->gno].p[$1->setno].setfillpen.color = prop;
3661 	}
3662 	| selectset FILL pattern_select
3663         {
3664 	    int prop = $3;
3665 
3666 	    if (get_project_version() <= 40102) {
3667                 switch (filltype_obs) {
3668                 case COLOR:
3669                     prop = 1;
3670                     break;
3671                 case PATTERN:
3672                     break;
3673                 default: /* NONE */
3674 	            prop = 0;
3675                     break;
3676                 }
3677 	    }
3678 	    g[$1->gno].p[$1->setno].setfillpen.pattern = prop;
3679 	}
3680 
3681 
3682 	| selectset BASELINE onoff
3683         {
3684 	    g[$1->gno].p[$1->setno].baseline = $3;
3685 	}
3686 	| selectset BASELINE TYPE nexpr
3687         {
3688 	    g[$1->gno].p[$1->setno].baseline_type = $4;
3689 	}
3690 
3691 	| selectset DROPLINE onoff
3692         {
3693 	    g[$1->gno].p[$1->setno].dropline = $3;
3694 	}
3695 
3696 	| selectset AVALUE onoff
3697         {
3698 	    g[$1->gno].p[$1->setno].avalue.active = $3;
3699 	}
3700 	| selectset AVALUE TYPE nexpr
3701         {
3702 	    g[$1->gno].p[$1->setno].avalue.type = $4;
3703 	}
3704 	| selectset AVALUE CHAR SIZE expr
3705         {
3706 	    g[$1->gno].p[$1->setno].avalue.size = $5;
3707 	}
3708 	| selectset AVALUE font_select
3709         {
3710 	    g[$1->gno].p[$1->setno].avalue.font = $3;
3711 	}
3712 	| selectset AVALUE color_select
3713         {
3714 	    g[$1->gno].p[$1->setno].avalue.color = $3;
3715 	}
3716 	| selectset AVALUE ROT nexpr
3717         {
3718 	    g[$1->gno].p[$1->setno].avalue.angle = $4;
3719 	}
3720 	| selectset AVALUE FORMAT formatchoice
3721         {
3722 	    g[$1->gno].p[$1->setno].avalue.format = $4;
3723 	}
3724 	| selectset AVALUE PREC nexpr
3725         {
3726 	    g[$1->gno].p[$1->setno].avalue.prec = $4;
3727 	}
3728 	| selectset AVALUE OFFSET expr ',' expr {
3729 	    g[$1->gno].p[$1->setno].avalue.offset.x = $4;
3730 	    g[$1->gno].p[$1->setno].avalue.offset.y = $6;
3731 	}
3732 	| selectset AVALUE PREPEND sexpr
3733         {
3734 	    strcpy(g[$1->gno].p[$1->setno].avalue.prestr, $4);
3735 	    xfree($4);
3736 	}
3737 	| selectset AVALUE APPEND sexpr
3738         {
3739 	    strcpy(g[$1->gno].p[$1->setno].avalue.appstr, $4);
3740 	    xfree($4);
3741 	}
3742 
3743 	| selectset ERRORBAR onoff {
3744 	    g[$1->gno].p[$1->setno].errbar.active = $3;
3745 	}
3746 	| selectset ERRORBAR opchoice_sel {
3747 	    g[$1->gno].p[$1->setno].errbar.ptype = $3;
3748 	}
3749 	| selectset ERRORBAR color_select {
3750 	    g[$1->gno].p[$1->setno].errbar.pen.color = $3;
3751 	}
3752 	| selectset ERRORBAR pattern_select {
3753 	    g[$1->gno].p[$1->setno].errbar.pen.pattern = $3;
3754 	}
3755 	| selectset ERRORBAR SIZE expr {
3756             g[$1->gno].p[$1->setno].errbar.barsize = $4;
3757 	}
3758 	| selectset ERRORBAR linew_select {
3759             g[$1->gno].p[$1->setno].errbar.linew = $3;
3760 	}
3761 	| selectset ERRORBAR lines_select {
3762             g[$1->gno].p[$1->setno].errbar.lines = $3;
3763 	}
3764 	| selectset ERRORBAR RISER linew_select {
3765             g[$1->gno].p[$1->setno].errbar.riser_linew = $4;
3766 	}
3767 	| selectset ERRORBAR RISER lines_select {
3768             g[$1->gno].p[$1->setno].errbar.riser_lines = $4;
3769 	}
3770 	| selectset ERRORBAR RISER CLIP onoff {
3771             g[$1->gno].p[$1->setno].errbar.arrow_clip = $5;
3772 	}
3773 	| selectset ERRORBAR RISER CLIP LENGTH expr {
3774             g[$1->gno].p[$1->setno].errbar.cliplen = $6;
3775 	}
3776 
3777 	| selectset COMMENT sexpr {
3778 	    strncpy(g[$1->gno].p[$1->setno].comments, $3, MAX_STRING_LENGTH - 1);
3779 	    xfree($3);
3780 	}
3781 
3782 	| selectset LEGEND sexpr {
3783 	    strncpy(g[$1->gno].p[$1->setno].lstr, $3, MAX_STRING_LENGTH - 1);
3784 	    xfree($3);
3785 	}
3786 	;
3787 
3788 
3789 axisfeature:
3790 	onoff {
3791 	    if (!is_valid_axis(whichgraph, naxis)) {
3792                 yyerror("No valid axis selected");
3793                 return 1;
3794             }
3795 	    g[whichgraph].t[naxis]->active = $1;
3796 	}
3797 	| TYPE ZERO onoff {
3798 	    if (!is_valid_axis(whichgraph, naxis)) {
3799                 yyerror("No valid axis selected");
3800                 return 1;
3801             }
3802 	    g[whichgraph].t[naxis]->zero = $3;
3803 	}
3804 	| TICKP tickattr {}
3805 	| TICKP tickattr_obs {}
3806 	| TICKLABEL ticklabelattr {}
3807 	| TICKLABEL ticklabelattr_obs {}
3808 	| LABEL axislabeldesc {}
3809 	| LABEL axislabeldesc_obs {}
3810 	| BAR axisbardesc {}
3811 	| OFFSET expr ',' expr {
3812 	    if (!is_valid_axis(whichgraph, naxis)) {
3813                 yyerror("No valid axis selected");
3814                 return 1;
3815             }
3816             g[whichgraph].t[naxis]->offsx = $2;
3817 	    g[whichgraph].t[naxis]->offsy = $4;
3818 	}
3819 	;
3820 
3821 tickattr:
3822 	onoff {
3823 	    if (!is_valid_axis(whichgraph, naxis)) {
3824                 yyerror("No valid axis selected");
3825                 return 1;
3826             }
3827 	    g[whichgraph].t[naxis]->t_flag = $1;
3828 	}
3829 	| MAJOR expr {
3830 	    if (!is_valid_axis(whichgraph, naxis)) {
3831                 yyerror("No valid axis selected");
3832                 return 1;
3833             }
3834             g[whichgraph].t[naxis]->tmajor = $2;
3835 	}
3836 	| MINOR TICKSP nexpr {
3837 	    if (!is_valid_axis(whichgraph, naxis)) {
3838                 yyerror("No valid axis selected");
3839                 return 1;
3840             }
3841 	    g[whichgraph].t[naxis]->nminor = $3;
3842 	}
3843 	| PLACE ROUNDED onoff {
3844 	    if (!is_valid_axis(whichgraph, naxis)) {
3845                 yyerror("No valid axis selected");
3846                 return 1;
3847             }
3848 	    g[whichgraph].t[naxis]->t_round = $3;
3849 	}
3850 
3851 	| OFFSETX expr {
3852 	    if (!is_valid_axis(whichgraph, naxis)) {
3853                 yyerror("No valid axis selected");
3854                 return 1;
3855             }
3856             g[whichgraph].t[naxis]->offsx = $2;
3857 	}
3858 	| OFFSETY expr {
3859 	    if (!is_valid_axis(whichgraph, naxis)) {
3860                 yyerror("No valid axis selected");
3861                 return 1;
3862             }
3863             g[whichgraph].t[naxis]->offsy = $2;
3864 	}
3865 	| DEFAULT nexpr {
3866 	    if (!is_valid_axis(whichgraph, naxis)) {
3867                 yyerror("No valid axis selected");
3868                 return 1;
3869             }
3870 	    g[whichgraph].t[naxis]->t_autonum = $2;
3871 	}
3872 	| inoutchoice {
3873 	    if (!is_valid_axis(whichgraph, naxis)) {
3874                 yyerror("No valid axis selected");
3875                 return 1;
3876             }
3877 	    g[whichgraph].t[naxis]->t_inout = $1;
3878 	}
3879 	| MAJOR SIZE expr {
3880 	    if (!is_valid_axis(whichgraph, naxis)) {
3881                 yyerror("No valid axis selected");
3882                 return 1;
3883             }
3884 	    g[whichgraph].t[naxis]->props.size = $3;
3885 	}
3886 	| MINOR SIZE expr {
3887 	    if (!is_valid_axis(whichgraph, naxis)) {
3888                 yyerror("No valid axis selected");
3889                 return 1;
3890             }
3891 	    g[whichgraph].t[naxis]->mprops.size = $3;
3892 	}
3893 	| color_select {
3894 	    if (!is_valid_axis(whichgraph, naxis)) {
3895                 yyerror("No valid axis selected");
3896                 return 1;
3897             }
3898 	    g[whichgraph].t[naxis]->props.color = g[whichgraph].t[naxis]->mprops.color = $1;
3899 	}
3900 	| MAJOR color_select {
3901 	    if (!is_valid_axis(whichgraph, naxis)) {
3902                 yyerror("No valid axis selected");
3903                 return 1;
3904             }
3905 	    g[whichgraph].t[naxis]->props.color = $2;
3906 	}
3907 	| MINOR color_select {
3908 	    if (!is_valid_axis(whichgraph, naxis)) {
3909                 yyerror("No valid axis selected");
3910                 return 1;
3911             }
3912 	    g[whichgraph].t[naxis]->mprops.color = $2;
3913 	}
3914 	| linew_select {
3915 	    if (!is_valid_axis(whichgraph, naxis)) {
3916                 yyerror("No valid axis selected");
3917                 return 1;
3918             }
3919 	    g[whichgraph].t[naxis]->props.linew = g[whichgraph].t[naxis]->mprops.linew = $1;
3920 	}
3921 	| MAJOR linew_select {
3922 	    if (!is_valid_axis(whichgraph, naxis)) {
3923                 yyerror("No valid axis selected");
3924                 return 1;
3925             }
3926 	    g[whichgraph].t[naxis]->props.linew = $2;
3927 	}
3928 	| MINOR linew_select {
3929 	    if (!is_valid_axis(whichgraph, naxis)) {
3930                 yyerror("No valid axis selected");
3931                 return 1;
3932             }
3933 	    g[whichgraph].t[naxis]->mprops.linew = $2;
3934 	}
3935 	| MAJOR lines_select {
3936 	    if (!is_valid_axis(whichgraph, naxis)) {
3937                 yyerror("No valid axis selected");
3938                 return 1;
3939             }
3940 	    g[whichgraph].t[naxis]->props.lines = $2;
3941 	}
3942 	| MINOR lines_select {
3943 	    if (!is_valid_axis(whichgraph, naxis)) {
3944                 yyerror("No valid axis selected");
3945                 return 1;
3946             }
3947 	    g[whichgraph].t[naxis]->mprops.lines = $2;
3948 	}
3949 	| MAJOR GRID onoff {
3950 	    if (!is_valid_axis(whichgraph, naxis)) {
3951                 yyerror("No valid axis selected");
3952                 return 1;
3953             }
3954 	    g[whichgraph].t[naxis]->props.gridflag = $3;
3955 	}
3956 	| MINOR GRID onoff {
3957 	    if (!is_valid_axis(whichgraph, naxis)) {
3958                 yyerror("No valid axis selected");
3959                 return 1;
3960             }
3961 	    g[whichgraph].t[naxis]->mprops.gridflag = $3;
3962 	}
3963 	| opchoice_sel {
3964 	    if (!is_valid_axis(whichgraph, naxis)) {
3965                 yyerror("No valid axis selected");
3966                 return 1;
3967             }
3968 	    g[whichgraph].t[naxis]->t_op = $1;
3969 	}
3970 	| SPEC TYPE tickspectype {
3971 	    if (!is_valid_axis(whichgraph, naxis)) {
3972                 yyerror("No valid axis selected");
3973                 return 1;
3974             }
3975 	    g[whichgraph].t[naxis]->t_spec = $3;
3976 	}
3977 	| SPEC nexpr {
3978 	    if (!is_valid_axis(whichgraph, naxis)) {
3979                 yyerror("No valid axis selected");
3980                 return 1;
3981             }
3982 	    g[whichgraph].t[naxis]->nticks = $2;
3983 	}
3984 	| MAJOR nexpr ',' expr {
3985 	    if (!is_valid_axis(whichgraph, naxis)) {
3986                 yyerror("No valid axis selected");
3987                 return 1;
3988             }
3989 	    g[whichgraph].t[naxis]->tloc[$2].wtpos = $4;
3990 	    g[whichgraph].t[naxis]->tloc[$2].type = TICK_TYPE_MAJOR;
3991 	}
3992 	| MINOR nexpr ',' expr {
3993 	    if (!is_valid_axis(whichgraph, naxis)) {
3994                 yyerror("No valid axis selected");
3995                 return 1;
3996             }
3997 	    g[whichgraph].t[naxis]->tloc[$2].wtpos = $4;
3998 	    g[whichgraph].t[naxis]->tloc[$2].type = TICK_TYPE_MINOR;
3999 	}
4000 	;
4001 
4002 ticklabelattr:
4003 	onoff {
4004 	    if (!is_valid_axis(whichgraph, naxis)) {
4005                 yyerror("No valid axis selected");
4006                 return 1;
4007             }
4008 	    g[whichgraph].t[naxis]->tl_flag = $1;
4009 	}
4010 	| PREC nexpr {
4011 	    if (!is_valid_axis(whichgraph, naxis)) {
4012                 yyerror("No valid axis selected");
4013                 return 1;
4014             }
4015 	    g[whichgraph].t[naxis]->tl_prec = $2;
4016 	}
4017 	| FORMAT formatchoice {
4018 	    if (!is_valid_axis(whichgraph, naxis)) {
4019                 yyerror("No valid axis selected");
4020                 return 1;
4021             }
4022 	    g[whichgraph].t[naxis]->tl_format = $2;
4023 	}
4024 	| FORMAT expr {
4025 	    if (!is_valid_axis(whichgraph, naxis)) {
4026                 yyerror("No valid axis selected");
4027                 return 1;
4028             }
4029 	    g[whichgraph].t[naxis]->tl_format = $2;
4030 	}
4031 	| APPEND sexpr {
4032 	    if (!is_valid_axis(whichgraph, naxis)) {
4033                 yyerror("No valid axis selected");
4034                 return 1;
4035             }
4036 	    strcpy(g[whichgraph].t[naxis]->tl_appstr, $2);
4037 	    xfree($2);
4038 	}
4039 	| PREPEND sexpr {
4040 	    if (!is_valid_axis(whichgraph, naxis)) {
4041                 yyerror("No valid axis selected");
4042                 return 1;
4043             }
4044 	    strcpy(g[whichgraph].t[naxis]->tl_prestr, $2);
4045 	    xfree($2);
4046 	}
4047 	| ANGLE nexpr {
4048 	    if (!is_valid_axis(whichgraph, naxis)) {
4049                 yyerror("No valid axis selected");
4050                 return 1;
4051             }
4052 	    g[whichgraph].t[naxis]->tl_angle = $2;
4053 	}
4054 	| SKIP nexpr {
4055 	    if (!is_valid_axis(whichgraph, naxis)) {
4056                 yyerror("No valid axis selected");
4057                 return 1;
4058             }
4059 	    g[whichgraph].t[naxis]->tl_skip = $2;
4060 	}
4061 	| STAGGER nexpr {
4062 	    if (!is_valid_axis(whichgraph, naxis)) {
4063                 yyerror("No valid axis selected");
4064                 return 1;
4065             }
4066 	    g[whichgraph].t[naxis]->tl_staggered = $2;
4067 	}
4068 	| opchoice_sel {
4069 	    if (!is_valid_axis(whichgraph, naxis)) {
4070                 yyerror("No valid axis selected");
4071                 return 1;
4072             }
4073 	    g[whichgraph].t[naxis]->tl_op = $1;
4074 	}
4075 	| FORMULA sexpr {
4076 	    if (!is_valid_axis(whichgraph, naxis)) {
4077                 yyerror("No valid axis selected");
4078                 return 1;
4079             }
4080             g[whichgraph].t[naxis]->tl_formula =
4081                 copy_string(g[whichgraph].t[naxis]->tl_formula, $2);
4082             xfree($2);
4083 	}
4084 	| START expr {
4085 	    if (!is_valid_axis(whichgraph, naxis)) {
4086                 yyerror("No valid axis selected");
4087                 return 1;
4088             }
4089 	    g[whichgraph].t[naxis]->tl_start = $2;
4090 	}
4091 	| STOP expr {
4092 	    if (!is_valid_axis(whichgraph, naxis)) {
4093                 yyerror("No valid axis selected");
4094                 return 1;
4095             }
4096 	    g[whichgraph].t[naxis]->tl_stop = $2;
4097 	}
4098 	| START TYPE SPEC {
4099 	    if (!is_valid_axis(whichgraph, naxis)) {
4100                 yyerror("No valid axis selected");
4101                 return 1;
4102             }
4103 	    g[whichgraph].t[naxis]->tl_starttype = TYPE_SPEC;
4104 	}
4105 	| START TYPE AUTO {
4106 	    if (!is_valid_axis(whichgraph, naxis)) {
4107                 yyerror("No valid axis selected");
4108                 return 1;
4109             }
4110 	    g[whichgraph].t[naxis]->tl_starttype = TYPE_AUTO;
4111 	}
4112 	| STOP TYPE SPEC {
4113 	    if (!is_valid_axis(whichgraph, naxis)) {
4114                 yyerror("No valid axis selected");
4115                 return 1;
4116             }
4117 	    g[whichgraph].t[naxis]->tl_stoptype = TYPE_SPEC;
4118 	}
4119 	| STOP TYPE AUTO {
4120 	    if (!is_valid_axis(whichgraph, naxis)) {
4121                 yyerror("No valid axis selected");
4122                 return 1;
4123             }
4124 	    g[whichgraph].t[naxis]->tl_stoptype = TYPE_AUTO;
4125 	}
4126 	| CHAR SIZE expr {
4127 	    if (!is_valid_axis(whichgraph, naxis)) {
4128                 yyerror("No valid axis selected");
4129                 return 1;
4130             }
4131 	    g[whichgraph].t[naxis]->tl_charsize = $3;
4132 	}
4133 	| font_select {
4134 	    if (!is_valid_axis(whichgraph, naxis)) {
4135                 yyerror("No valid axis selected");
4136                 return 1;
4137             }
4138 	    g[whichgraph].t[naxis]->tl_font = $1;
4139 	}
4140 	| color_select {
4141 	    if (!is_valid_axis(whichgraph, naxis)) {
4142                 yyerror("No valid axis selected");
4143                 return 1;
4144             }
4145 	    g[whichgraph].t[naxis]->tl_color = $1;
4146 	}
4147 	| nexpr ',' sexpr {
4148 	    if (!is_valid_axis(whichgraph, naxis)) {
4149                 yyerror("No valid axis selected");
4150                 xfree($3);
4151                 return 1;
4152             }
4153 	    if ($1 >= MAX_TICKS) {
4154 	         yyerror("Number of ticks exceeds maximum");
4155 	         xfree($3);
4156 	         return 1;
4157 	    }
4158 	    g[whichgraph].t[naxis]->tloc[$1].label =
4159                 copy_string(g[whichgraph].t[naxis]->tloc[$1].label, $3);
4160 	    xfree($3);
4161 	}
4162 	| OFFSET AUTO {
4163 	    if (!is_valid_axis(whichgraph, naxis)) {
4164                 yyerror("No valid axis selected");
4165                 return 1;
4166             }
4167 	    g[whichgraph].t[naxis]->tl_gaptype = TYPE_AUTO;
4168 	}
4169 	| OFFSET SPEC {
4170 	    if (!is_valid_axis(whichgraph, naxis)) {
4171                 yyerror("No valid axis selected");
4172                 return 1;
4173             }
4174 	    g[whichgraph].t[naxis]->tl_gaptype = TYPE_SPEC;
4175 	}
4176 	| OFFSET expr ',' expr {
4177 	    if (!is_valid_axis(whichgraph, naxis)) {
4178                 yyerror("No valid axis selected");
4179                 return 1;
4180             }
4181 	    g[whichgraph].t[naxis]->tl_gap.x = $2;
4182 	    g[whichgraph].t[naxis]->tl_gap.y = $4;
4183 	}
4184 	;
4185 
4186 axislabeldesc:
4187 	sexpr {
4188 	    if (!is_valid_axis(whichgraph, naxis)) {
4189                 yyerror("No valid axis selected");
4190                 return 1;
4191             }
4192 	    set_plotstr_string(&g[whichgraph].t[naxis]->label, $1);
4193 	    xfree($1);
4194 	}
4195 	| LAYOUT PERP {
4196 	    if (!is_valid_axis(whichgraph, naxis)) {
4197                 yyerror("No valid axis selected");
4198                 return 1;
4199             }
4200 	    g[whichgraph].t[naxis]->label_layout = LAYOUT_PERPENDICULAR;
4201 	}
4202 	| LAYOUT PARA {
4203 	    if (!is_valid_axis(whichgraph, naxis)) {
4204                 yyerror("No valid axis selected");
4205                 return 1;
4206             }
4207 	    g[whichgraph].t[naxis]->label_layout = LAYOUT_PARALLEL;
4208 	}
4209 	| PLACE AUTO {
4210 	    if (!is_valid_axis(whichgraph, naxis)) {
4211                 yyerror("No valid axis selected");
4212                 return 1;
4213             }
4214 	    g[whichgraph].t[naxis]->label_place = TYPE_AUTO;
4215 	}
4216 	| PLACE SPEC {
4217 	    if (!is_valid_axis(whichgraph, naxis)) {
4218                 yyerror("No valid axis selected");
4219                 return 1;
4220             }
4221 	    g[whichgraph].t[naxis]->label_place = TYPE_SPEC;
4222 	}
4223 	| PLACE expr ',' expr {
4224 	    if (!is_valid_axis(whichgraph, naxis)) {
4225                 yyerror("No valid axis selected");
4226                 return 1;
4227             }
4228 	    g[whichgraph].t[naxis]->label.x = $2;
4229 	    g[whichgraph].t[naxis]->label.y = $4;
4230 	}
4231 	| JUST justchoice {
4232 	    if (!is_valid_axis(whichgraph, naxis)) {
4233                 yyerror("No valid axis selected");
4234                 return 1;
4235             }
4236 	    g[whichgraph].t[naxis]->label.just = $2;
4237 	}
4238 	| CHAR SIZE expr {
4239 	    if (!is_valid_axis(whichgraph, naxis)) {
4240                 yyerror("No valid axis selected");
4241                 return 1;
4242             }
4243 	    g[whichgraph].t[naxis]->label.charsize = $3;
4244 	}
4245 	| font_select {
4246 	    if (!is_valid_axis(whichgraph, naxis)) {
4247                 yyerror("No valid axis selected");
4248                 return 1;
4249             }
4250 	    g[whichgraph].t[naxis]->label.font = $1;
4251 	}
4252 	| color_select {
4253 	    if (!is_valid_axis(whichgraph, naxis)) {
4254                 yyerror("No valid axis selected");
4255                 return 1;
4256             }
4257 	    g[whichgraph].t[naxis]->label.color = $1;
4258 	}
4259 	| opchoice_sel {
4260 	    if (!is_valid_axis(whichgraph, naxis)) {
4261                 yyerror("No valid axis selected");
4262                 return 1;
4263             }
4264 	    g[whichgraph].t[naxis]->label_op = $1;
4265 	}
4266 	;
4267 
4268 axisbardesc:
4269 	onoff {
4270 	    if (!is_valid_axis(whichgraph, naxis)) {
4271                 yyerror("No valid axis selected");
4272                 return 1;
4273             }
4274 	    g[whichgraph].t[naxis]->t_drawbar = $1;
4275 	}
4276 	| color_select {
4277 	    if (!is_valid_axis(whichgraph, naxis)) {
4278                 yyerror("No valid axis selected");
4279                 return 1;
4280             }
4281 	    g[whichgraph].t[naxis]->t_drawbarcolor = $1;
4282 	}
4283 	| lines_select {
4284 	    if (!is_valid_axis(whichgraph, naxis)) {
4285                 yyerror("No valid axis selected");
4286                 return 1;
4287             }
4288 	    g[whichgraph].t[naxis]->t_drawbarlines = $1;
4289 	}
4290 	| linew_select {
4291 	    if (!is_valid_axis(whichgraph, naxis)) {
4292                 yyerror("No valid axis selected");
4293                 return 1;
4294             }
4295 	    g[whichgraph].t[naxis]->t_drawbarlinew = $1;
4296 	}
4297 	;
4298 
4299 nonlfitopts:
4300         TITLE sexpr {
4301           nonl_opts.title = copy_string(nonl_opts.title, $2);
4302 	  xfree($2);
4303         }
4304         | FORMULA sexpr {
4305           nonl_opts.formula = copy_string(nonl_opts.formula, $2);
4306 	  xfree($2);
4307         }
4308         | WITH nexpr PARAMETERS {
4309             nonl_opts.parnum = $2;
4310         }
4311         | PREC expr {
4312             nonl_opts.tolerance = $2;
4313         }
4314         ;
4315 
4316 selectgraph:
4317         GRAPHNO
4318         {
4319             $$ = $1;
4320         }
4321         | GRAPH indx
4322         {
4323             $$ = $2;
4324         }
4325         ;
4326 
4327 selectset:
4328 	selectgraph '.' SETNUM
4329 	{
4330 	    int gno = $1, setno = $3;
4331             if (allocate_set(gno, setno) == RETURN_SUCCESS) {
4332                 $$ = &trgt_pool[tgtn];
4333                 $$->gno   = gno;
4334                 $$->setno = setno;
4335                 tgtn++;
4336             } else {
4337                 errmsg("Can't allocate referred set");
4338                 return 1;
4339             }
4340 	}
4341 	| selectgraph '.' SET indx
4342 	{
4343 	    int gno = $1, setno = $4;
4344             if (allocate_set(gno, setno) == RETURN_SUCCESS) {
4345                 $$ = &trgt_pool[tgtn];
4346                 $$->gno   = gno;
4347                 $$->setno = setno;
4348                 tgtn++;
4349             } else {
4350                 errmsg("Can't allocate referred set");
4351                 return 1;
4352             }
4353 	}
4354 	| SETNUM
4355 	{
4356 	    int gno = whichgraph, setno = $1;
4357             if (allocate_set(gno, setno) == RETURN_SUCCESS) {
4358                 $$ = &trgt_pool[tgtn];
4359                 $$->gno   = gno;
4360                 $$->setno = setno;
4361                 tgtn++;
4362             } else {
4363                 errmsg("Can't allocate referred set");
4364                 return 1;
4365             }
4366 	}
4367 	| SET indx
4368 	{
4369 	    int gno = whichgraph, setno = $2;
4370             if (allocate_set(gno, setno) == RETURN_SUCCESS) {
4371                 $$ = &trgt_pool[tgtn];
4372                 $$->gno   = gno;
4373                 $$->setno = setno;
4374                 tgtn++;
4375             } else {
4376                 errmsg("Can't allocate referred set");
4377                 return 1;
4378             }
4379 	}
4380 	;
4381 
4382 setaxis:
4383 	axis axisfeature {}
4384 	| selectgraph axis axisfeature {}
4385 	;
4386 
4387 axis:
4388 	XAXIS { naxis =  X_AXIS; }
4389 	| YAXIS { naxis = Y_AXIS; }
4390 	| ALTXAXIS { naxis = ZX_AXIS; }
4391 	| ALTYAXIS { naxis = ZY_AXIS; }
4392 	;
4393 
4394 proctype:
4395         KEY_CONST         { $$ = CONSTANT;  }
4396         | KEY_UNIT        { $$ = UCONSTANT; }
4397         | KEY_FUNC_I      { $$ = FUNC_I;    }
4398 	| KEY_FUNC_D      { $$ = FUNC_D;    }
4399 	| KEY_FUNC_ND     { $$ = FUNC_ND;   }
4400 	| KEY_FUNC_NN     { $$ = FUNC_NN;   }
4401 	| KEY_FUNC_DD     { $$ = FUNC_DD;   }
4402 	| KEY_FUNC_NND    { $$ = FUNC_NND;  }
4403 	| KEY_FUNC_PPD    { $$ = FUNC_PPD;  }
4404 	| KEY_FUNC_PPPD   { $$ = FUNC_PPPD; }
4405 	| KEY_FUNC_PPPPD  { $$ = FUNC_PPPPD; }
4406 	| KEY_FUNC_PPPPPD { $$ = FUNC_PPPPPD; }
4407 	;
4408 
4409 tickspectype:
4410 	NONE { $$ =  TICKS_SPEC_NONE; }
4411 	| TICKSP { $$ = TICKS_SPEC_MARKS; }
4412 	| BOTH { $$ = TICKS_SPEC_BOTH; }
4413 	;
4414 
4415 filtertype:
4416         IFILTER       { $$ = FILTER_INPUT; }
4417 	| OFILTER    { $$ = FILTER_OUTPUT; }
4418 	;
4419 
4420 filtermethod:
4421         MAGIC         { $$ = FILTER_MAGIC; }
4422 	| PATTERN   { $$ = FILTER_PATTERN; }
4423 	;
4424 
4425 xytype:
4426 	XY { $$ = SET_XY; }
4427 	| BAR { $$ = SET_BAR; }
4428 	| BARDY { $$ = SET_BARDY; }
4429 	| BARDYDY { $$ = SET_BARDYDY; }
4430 	| XYZ { $$ = SET_XYZ; }
4431 	| XYDX { $$ = SET_XYDX; }
4432 	| XYDY { $$ = SET_XYDY; }
4433 	| XYDXDX { $$ = SET_XYDXDX; }
4434 	| XYDYDY { $$ = SET_XYDYDY; }
4435 	| XYDXDY { $$ = SET_XYDXDY; }
4436 	| XYDXDXDYDY { $$ = SET_XYDXDXDYDY; }
4437 	| XYHILO { $$ = SET_XYHILO; }
4438 	| XYR { $$ = SET_XYR; }
4439 	| XYSIZE { $$ = SET_XYSIZE; }
4440 	| XYCOLOR { $$ = SET_XYCOLOR; }
4441 	| XYCOLPAT { $$ = SET_XYCOLPAT; }
4442 	| XYVMAP { $$ = SET_XYVMAP; }
4443 	| XYBOXPLOT { $$ = SET_BOXPLOT; }
4444 	| XYSTRING { $$ = SET_XY; }
4445 	;
4446 
4447 graphtype:
4448 	XY { $$ = GRAPH_XY; }
4449 	| CHART { $$ = GRAPH_CHART; }
4450 	| POLAR { $$ = GRAPH_POLAR; }
4451 	| SMITH { $$ = GRAPH_SMITH; }
4452 	| FIXED { $$ = GRAPH_FIXED; }
4453 	| PIE   { $$ = GRAPH_PIE;   }
4454 	;
4455 
4456 pagelayout:
4457         FREE { $$ = PAGE_FREE; }
4458         | FIXED { $$ = PAGE_FIXED; }
4459         ;
4460 
4461 pageorient:
4462         LANDSCAPE  { $$ = PAGE_ORIENT_LANDSCAPE; }
4463         | PORTRAIT { $$ = PAGE_ORIENT_PORTRAIT;  }
4464         ;
4465 
4466 regiontype:
4467 	ABOVE { $$ = REGION_ABOVE; }
4468 	|  BELOW { $$ = REGION_BELOW; }
4469 	|  LEFT { $$ = REGION_TOLEFT; }
4470 	|  RIGHT { $$ = REGION_TORIGHT; }
4471 	|  POLYI { $$ = REGION_POLYI; }
4472 	|  POLYO { $$ = REGION_POLYO; }
4473 	|  HORIZI { $$ = REGION_HORIZI; }
4474 	|  VERTI { $$ = REGION_VERTI; }
4475 	|  HORIZO { $$ = REGION_HORIZO; }
4476 	|  VERTO { $$ = REGION_VERTO; }
4477 	;
4478 
4479 scaletype: NORMAL { $$ = SCALE_NORMAL; }
4480 	| LOGARITHMIC { $$ = SCALE_LOG; }
4481 	| RECIPROCAL { $$ = SCALE_REC; }
4482 	| LOGIT { $$ = SCALE_LOGIT; }
4483 	;
4484 
4485 onoff: ON { $$ = TRUE; }
4486 	| OFF { $$ = FALSE; }
4487 	;
4488 
4489 runtype: RUNAVG { $$ = RUN_AVG; }
4490 	| RUNSTD { $$ = RUN_STD; }
4491 	| RUNMED { $$ = RUN_MED; }
4492 	| RUNMAX { $$ = RUN_MAX; }
4493 	| RUNMIN { $$ = RUN_MIN; }
4494 	;
4495 
4496 sourcetype:
4497         DISK { $$ = SOURCE_DISK; }
4498 	| PIPE {
4499             if (!safe_mode) {
4500                 $$ = SOURCE_PIPE;
4501             } else {
4502                 yyerror("Pipe inputs are disabled in safe mode");
4503                 $$ = SOURCE_DISK;
4504             }
4505         }
4506 	;
4507 
4508 justchoice: RIGHT { $$ = JUST_RIGHT; }
4509 	| LEFT { $$ = JUST_LEFT; }
4510 	| CENTER { $$ = JUST_CENTER; }
4511 	;
4512 
4513 inoutchoice: IN { $$ = TICKS_IN; }
4514 	| OUT { $$ = TICKS_OUT; }
4515 	| BOTH { $$ = TICKS_BOTH; }
4516 	;
4517 
4518 formatchoice: DECIMAL { $$ = FORMAT_DECIMAL; }
4519 	| EXPONENTIAL { $$ = FORMAT_EXPONENTIAL; }
4520 	| GENERAL { $$ = FORMAT_GENERAL; }
4521 	| SCIENTIFIC { $$ = FORMAT_SCIENTIFIC; }
4522 	| ENGINEERING { $$ = FORMAT_ENGINEERING; }
4523 	| COMPUTING { $$ = FORMAT_COMPUTING; }
4524 	| POWER { $$ = FORMAT_POWER; }
4525 	| DDMMYY { $$ = FORMAT_DDMMYY; }
4526 	| MMDDYY { $$ = FORMAT_MMDDYY; }
4527 	| YYMMDD { $$ = FORMAT_YYMMDD; }
4528 	| MMYY { $$ = FORMAT_MMYY; }
4529 	| MMDD { $$ = FORMAT_MMDD; }
4530 	| MONTHDAY { $$ = FORMAT_MONTHDAY; }
4531 	| DAYMONTH { $$ = FORMAT_DAYMONTH; }
4532 	| MONTHS { $$ = FORMAT_MONTHS; }
4533 	| MONTHSY { $$ = FORMAT_MONTHSY; }
4534 	| MONTHL { $$ = FORMAT_MONTHL; }
4535 	| DAYOFWEEKS { $$ = FORMAT_DAYOFWEEKS; }
4536 	| DAYOFWEEKL { $$ = FORMAT_DAYOFWEEKL; }
4537 	| DAYOFYEAR { $$ = FORMAT_DAYOFYEAR; }
4538 	| HMS { $$ = FORMAT_HMS; }
4539 	| MMDDHMS { $$ = FORMAT_MMDDHMS; }
4540 	| MMDDYYHMS { $$ = FORMAT_MMDDYYHMS; }
4541 	| YYMMDDHMS { $$ = FORMAT_YYMMDDHMS; }
4542 	| DEGREESLON { $$ = FORMAT_DEGREESLON; }
4543 	| DEGREESMMLON { $$ = FORMAT_DEGREESMMLON; }
4544 	| DEGREESMMSSLON { $$ = FORMAT_DEGREESMMSSLON; }
4545 	| MMSSLON { $$ = FORMAT_MMSSLON; }
4546 	| DEGREESLAT { $$ = FORMAT_DEGREESLAT; }
4547 	| DEGREESMMLAT { $$ = FORMAT_DEGREESMMLAT; }
4548 	| DEGREESMMSSLAT { $$ = FORMAT_DEGREESMMSSLAT; }
4549 	| MMSSLAT { $$ = FORMAT_MMSSLAT; }
4550 	;
4551 
4552 signchoice: NORMAL { $$ = SIGN_NORMAL; }
4553 	| ABSOLUTE { $$ = SIGN_ABSOLUTE; }
4554 	| NEGATE { $$ = SIGN_NEGATE; }
4555 	;
4556 
4557 direction: UP { $$ = UP; }
4558 	| DOWN { $$ = DOWN; }
4559 	| RIGHT { $$ = RIGHT; }
4560 	| LEFT { $$ = LEFT; }
4561 	| IN { $$ = IN; }
4562 	| OUT { $$ = OUT; }
4563 	;
4564 
4565 worldview: WORLD { $$ = COORD_WORLD; }
4566 	| VIEW { $$ = COORD_VIEW; }
4567 	;
4568 
4569 datacolumn: X_TOK { $$ = DATA_X; }
4570 	| Y_TOK { $$ = DATA_Y; }
4571 	| X0 { $$ = DATA_X; }
4572 	| Y0 { $$ = DATA_Y; }
4573 	| Y1 { $$ = DATA_Y1; }
4574 	| Y2 { $$ = DATA_Y2; }
4575 	| Y3 { $$ = DATA_Y3; }
4576 	| Y4 { $$ = DATA_Y4; }
4577 	;
4578 
4579 sortdir: ASCENDING { $$ = ASCENDING; }
4580 	| DESCENDING { $$ = DESCENDING; }
4581 	;
4582 
4583 sorton: X_TOK { $$ = DATA_X; }
4584 	| Y_TOK { $$ = DATA_Y; }
4585 	;
4586 
4587 ffttype: DFT { $$ = FFT_DFT; }
4588 	| FFT { $$ = FFT_FFT; }
4589 	| INVDFT { $$ = FFT_INVDFT; }
4590 	| INVFFT { $$ = FFT_INVFFT; }
4591 	;
4592 
4593 fourierdata:
4594 	REAL {$$=0;}
4595 	| COMPLEX {$$=1;}
4596 	;
4597 
4598 fourierloadx:
4599 	INDEX {$$=0;}
4600 	| FREQUENCY {$$=1;}
4601 	| PERIOD {$$=2;}
4602 	;
4603 
4604 fourierloady:
4605 	MAGNITUDE {$$=0;}
4606 	| PHASE {$$=1;}
4607 	| COEFFICIENTS {$$=2;}
4608 	;
4609 
4610 windowtype:
4611 	NONE {$$=0;}
4612 	| TRIANGULAR {$$=1;}
4613 	| HANNING {$$=2;}
4614 	| WELCH {$$=3;}
4615 	| HAMMING {$$=4;}
4616 	| BLACKMAN {$$=5;}
4617 	| PARZEN {$$=6;}
4618 	;
4619 
4620 interpmethod:
4621         LINEAR    { $$ = INTERP_LINEAR; }
4622         | SPLINE  { $$ = INTERP_SPLINE; }
4623         | ASPLINE { $$ = INTERP_ASPLINE; }
4624 	;
4625 
4626 stattype: MINP { $$ = MINP; }
4627 	| MAXP { $$ = MAXP; }
4628         | AVG { $$ = AVG; }
4629 	| SD { $$ = SD; }
4630 	| SUM { $$ = SUM; }
4631 	| IMIN { $$ = IMIN; }
4632 	| IMAX { $$ = IMAX; }
4633 	;
4634 
4635 font_select:
4636         FONTP nexpr
4637         {
4638             $$ = get_mapped_font($2);
4639         }
4640         | FONTP sexpr
4641         {
4642             $$ = get_font_by_name($2);
4643             xfree($2);
4644         }
4645         ;
4646 
4647 lines_select:
4648         LINESTYLE nexpr
4649         {
4650 	    int lines = $2;
4651             if (lines >= 0 && lines < number_of_linestyles()) {
4652 	        $$ = lines;
4653 	    } else {
4654 	        errmsg("invalid linestyle");
4655 	        $$ = 1;
4656 	    }
4657         }
4658         ;
4659 
4660 pattern_select:
4661         PATTERN nexpr
4662         {
4663 	    int patno = $2;
4664             if (patno >= 0 && patno < number_of_patterns()) {
4665 	        $$ = patno;
4666 	    } else {
4667 	        errmsg("invalid pattern number");
4668 	        $$ = 1;
4669 	    }
4670         }
4671         ;
4672 
4673 color_select:
4674         COLOR nexpr
4675         {
4676             int c = $2;
4677             if (c >= 0 && c < number_of_colors()) {
4678                 $$ = c;
4679             } else {
4680                 errmsg("Invalid color ID");
4681                 $$ = 1;
4682             }
4683         }
4684         | COLOR sexpr
4685         {
4686             int c = get_color_by_name($2);
4687             if (c == BAD_COLOR) {
4688                 errmsg("Invalid color name");
4689                 c = 1;
4690             }
4691             xfree($2);
4692             $$ = c;
4693         }
4694         | COLOR '(' nexpr ',' nexpr ',' nexpr ')'
4695         {
4696             int c;
4697             CMap_entry cmap;
4698             cmap.rgb.red = $3;
4699             cmap.rgb.green = $5;
4700             cmap.rgb.blue = $7;
4701             cmap.ctype = COLOR_MAIN;
4702             cmap.cname = NULL;
4703             c = add_color(cmap);
4704             if (c == BAD_COLOR) {
4705                 errmsg("Can't allocate requested color");
4706                 c = 1;
4707             }
4708             $$ = c;
4709         }
4710         ;
4711 
4712 linew_select:
4713         LINEWIDTH expr
4714         {
4715             double linew;
4716             linew = $2;
4717             if (linew < 0.0) {
4718                 yyerror("Negative linewidth");
4719                 linew = 0.0;
4720             } else if (linew > MAX_LINEWIDTH) {
4721                 yyerror("Linewidth too large");
4722                 linew = MAX_LINEWIDTH;
4723             }
4724             $$ = linew;
4725         }
4726         ;
4727 
4728 opchoice_sel: PLACE opchoice
4729         {
4730             $$ = $2;
4731         }
4732         ;
4733 
4734 opchoice: NORMAL { $$ = PLACEMENT_NORMAL; }
4735 	| OPPOSITE { $$ = PLACEMENT_OPPOSITE; }
4736 	| BOTH { $$ = PLACEMENT_BOTH; }
4737 	;
4738 
4739 
4740 parmset_obs:
4741         PAGE LAYOUT pageorient
4742         {
4743             int wpp, hpp;
4744             if ($3 == PAGE_ORIENT_LANDSCAPE) {
4745                 wpp = 792;
4746                 hpp = 612;
4747             } else {
4748                 wpp = 612;
4749                 hpp = 792;
4750             }
4751             set_page_dimensions(wpp, hpp, FALSE);
4752         }
4753         | PAGE SIZE NUMBER NUMBER {
4754             set_page_dimensions((int) $3, (int) $4, FALSE);
4755         }
4756 	| PAGE nexpr {
4757 	    scroll_proc($2);
4758 	}
4759 	| PAGE INOUT nexpr {
4760 	    scrollinout_proc($3);
4761 	}
4762 
4763 	| DEFAULT FONTP SOURCE expr {
4764 	}
4765 
4766 	| STACK WORLD expr ',' expr ',' expr ',' expr TICKP expr ',' expr ',' expr ',' expr
4767 	{
4768 	    add_world(whichgraph, $3, $5, $7, $9);
4769 	}
4770 
4771 	| BOX FILL colpat_obs {filltype_obs = $3;}
4772 
4773 	| ELLIPSE FILL colpat_obs {filltype_obs = $3;}
4774 
4775 	| STRING linew_select { }
4776 
4777 	| TIMESTAMP linew_select { }
4778 
4779 	| TITLE linew_select { }
4780 	| SUBTITLE linew_select { }
4781 
4782 	| LEGEND BOX onoff {
4783 	    if (!is_valid_gno(whichgraph)) {
4784                 yyerror("No valid graph selected");
4785                 return 1;
4786             }
4787 	    if ($3 == FALSE && get_project_version() <= 40102) {
4788                 g[whichgraph].l.boxpen.pattern = 0;
4789             }
4790 	}
4791 	| LEGEND X1 expr {
4792 	    if (!is_valid_gno(whichgraph)) {
4793                 yyerror("No valid graph selected");
4794                 return 1;
4795             }
4796 	    g[whichgraph].l.legx = $3;
4797 	}
4798 	| LEGEND Y1 expr {
4799 	    if (!is_valid_gno(whichgraph)) {
4800                 yyerror("No valid graph selected");
4801                 return 1;
4802             }
4803 	    g[whichgraph].l.legy = $3;
4804 	}
4805 	| LEGEND STRING nexpr sexpr {
4806 	    if (is_valid_setno(whichgraph, $3)) {
4807                 strncpy(g[whichgraph].p[$3].lstr, $4, MAX_STRING_LENGTH - 1);
4808 	    } else {
4809                 yyerror("Unallocated set");
4810             }
4811             xfree($4);
4812 	}
4813 	| LEGEND BOX FILL onoff { }
4814 	| LEGEND BOX FILL WITH colpat_obs {filltype_obs = $5;}
4815 	| LEGEND lines_select { }
4816 	| LEGEND linew_select { }
4817 
4818 	| selectgraph LABEL onoff { }
4819 
4820 	| selectgraph TYPE LOGX {
4821 	    g[$1].type = GRAPH_XY;
4822 	    g[$1].xscale = SCALE_LOG;
4823 	}
4824 	| selectgraph TYPE LOGY {
4825 	    g[$1].type = GRAPH_XY;
4826 	    g[$1].yscale = SCALE_LOG;
4827 	}
4828 	| selectgraph TYPE LOGXY
4829 	{
4830 	    g[$1].type = GRAPH_XY;
4831 	    g[$1].xscale = SCALE_LOG;
4832 	    g[$1].yscale = SCALE_LOG;
4833 	}
4834 	| selectgraph TYPE BAR
4835 	{
4836 	    g[$1].type = GRAPH_CHART;
4837 	    g[$1].xyflip = FALSE;
4838 	    g[$1].stacked = FALSE;
4839 	}
4840 	| selectgraph TYPE HBAR
4841 	{
4842 	    g[$1].type = GRAPH_CHART;
4843 	    g[$1].xyflip = TRUE;
4844 	}
4845 	| selectgraph TYPE STACKEDBAR
4846 	{
4847 	    g[$1].type = GRAPH_CHART;
4848 	    g[$1].stacked = TRUE;
4849 	}
4850 	| selectgraph TYPE STACKEDHBAR
4851 	{
4852 	    g[$1].type = GRAPH_CHART;
4853 	    g[$1].stacked = TRUE;
4854 	    g[$1].xyflip = TRUE;
4855 	}
4856 
4857 	| WORLD XMIN expr {
4858 	    if (!is_valid_gno(whichgraph)) {
4859                 yyerror("No valid graph selected");
4860                 return 1;
4861             }
4862 	    g[whichgraph].w.xg1 = $3;
4863 	}
4864 	| WORLD XMAX expr {
4865 	    if (!is_valid_gno(whichgraph)) {
4866                 yyerror("No valid graph selected");
4867                 return 1;
4868             }
4869 	    g[whichgraph].w.xg2 = $3;
4870 	}
4871 	| WORLD YMIN expr {
4872 	    if (!is_valid_gno(whichgraph)) {
4873                 yyerror("No valid graph selected");
4874                 return 1;
4875             }
4876 	    g[whichgraph].w.yg1 = $3;
4877 	}
4878 	| WORLD YMAX expr {
4879 	    if (!is_valid_gno(whichgraph)) {
4880                 yyerror("No valid graph selected");
4881                 return 1;
4882             }
4883 	    g[whichgraph].w.yg2 = $3;
4884 	}
4885 
4886 	| VIEW XMIN expr {
4887 	    if (!is_valid_gno(whichgraph)) {
4888                 yyerror("No valid graph selected");
4889                 return 1;
4890             }
4891 	    g[whichgraph].v.xv1 = $3;
4892 	}
4893 	| VIEW XMAX expr {
4894 	    if (!is_valid_gno(whichgraph)) {
4895                 yyerror("No valid graph selected");
4896                 return 1;
4897             }
4898 	    g[whichgraph].v.xv2 = $3;
4899 	}
4900 	| VIEW YMIN expr {
4901 	    if (!is_valid_gno(whichgraph)) {
4902                 yyerror("No valid graph selected");
4903                 return 1;
4904             }
4905 	    g[whichgraph].v.yv1 = $3;
4906 	}
4907 	| VIEW YMAX expr {
4908 	    if (!is_valid_gno(whichgraph)) {
4909                 yyerror("No valid graph selected");
4910                 return 1;
4911             }
4912 	    g[whichgraph].v.yv2 = $3;
4913 	}
4914 
4915 	| LEGEND LAYOUT expr {
4916 	}
4917 
4918 	| FRAMEP FILL onoff {
4919 	    if (!is_valid_gno(whichgraph)) {
4920                 yyerror("No valid graph selected");
4921                 return 1;
4922             }
4923             g[whichgraph].f.fillpen.pattern = $3;
4924         }
4925 
4926 	| selectgraph AUTOSCALE TYPE AUTO {
4927         }
4928 	| selectgraph AUTOSCALE TYPE SPEC {
4929         }
4930 
4931 	| LINE ARROW SIZE expr {
4932 	    line_asize = 2.0*$4;
4933 	}
4934 
4935         | HARDCOPY DEVICE expr { }
4936         | PS LINEWIDTH BEGIN expr { }
4937         | PS LINEWIDTH INCREMENT expr { }
4938         | PS linew_select { }
4939         ;
4940 
4941 
4942 axislabeldesc_obs:
4943 	linew_select { }
4944 	| opchoice_sel_obs {
4945 	    if (!is_valid_axis(whichgraph, naxis)) {
4946                 yyerror("No valid axis selected");
4947                 return 1;
4948             }
4949 	    g[whichgraph].t[naxis]->label_op = $1;
4950 	}
4951         ;
4952 
4953 setprop_obs:
4954 	selectset SYMBOL FILL nexpr {
4955 	    switch ($4){
4956 	    case 0:
4957 	        g[$1->gno].p[$1->setno].symfillpen.pattern = 0;
4958 	        break;
4959 	    case 1:
4960 	        g[$1->gno].p[$1->setno].symfillpen.pattern = 1;
4961 	        break;
4962 	    case 2:
4963 	        g[$1->gno].p[$1->setno].symfillpen.pattern = 1;
4964 	        g[$1->gno].p[$1->setno].symfillpen.color = getbgcolor();
4965 	        break;
4966 	    }
4967 	}
4968 	| selectset SKIP nexpr
4969         {
4970 	    g[$1->gno].p[$1->setno].symskip = $3;
4971 	}
4972 	| selectset FILL nexpr
4973         {
4974 	    switch ($3) {
4975             case 0:
4976                 g[$1->gno].p[$1->setno].filltype = SETFILL_NONE;
4977                 break;
4978             case 1:
4979                 g[$1->gno].p[$1->setno].filltype = SETFILL_POLYGON;
4980                 break;
4981             case 2:
4982                 g[$1->gno].p[$1->setno].filltype = SETFILL_BASELINE;
4983                 g[$1->gno].p[$1->setno].baseline_type = BASELINE_TYPE_0;
4984                 break;
4985             case 6:
4986                 g[$1->gno].p[$1->setno].filltype = SETFILL_BASELINE;
4987                 g[$1->gno].p[$1->setno].baseline_type = BASELINE_TYPE_GMIN;
4988                 break;
4989             case 7:
4990                 g[$1->gno].p[$1->setno].filltype = SETFILL_BASELINE;
4991                 g[$1->gno].p[$1->setno].baseline_type = BASELINE_TYPE_GMAX;
4992                 break;
4993             }
4994 	}
4995 	| selectset ERRORBAR TYPE opchoice_obs {
4996 	    g[$1->gno].p[$1->setno].errbar.ptype = $4;
4997 	}
4998 /*
4999  * 	| selectset SYMBOL COLOR '-' N_NUMBER {
5000  * 	    g[$1->gno].p[$1->setno].sympen.color = -1;
5001  * 	}
5002  */
5003 	| selectset SYMBOL CENTER onoff { }
5004 	| selectset lines_select {
5005 	    g[$1->gno].p[$1->setno].lines = $2;
5006 	}
5007 	| selectset linew_select {
5008 	    g[$1->gno].p[$1->setno].linew = $2;
5009 	}
5010 	| selectset color_select {
5011 	    g[$1->gno].p[$1->setno].linepen.color = $2;
5012 	}
5013 	| selectset FILL WITH colpat_obs {filltype_obs = $4;}
5014 	| selectset XYZ expr ',' expr { }
5015 	| selectset ERRORBAR LENGTH expr {
5016             g[$1->gno].p[$1->setno].errbar.barsize = $4;
5017 	}
5018 	| selectset ERRORBAR RISER onoff { }
5019         ;
5020 
5021 
5022 tickattr_obs:
5023 	MAJOR onoff {
5024 	    /* <= xmgr-4.1 */
5025 	    if (!is_valid_axis(whichgraph, naxis)) {
5026                 yyerror("No valid axis selected");
5027                 return 1;
5028             }
5029 	    g[whichgraph].t[naxis]->active = $2;
5030 	}
5031 	| MINOR onoff { }
5032 	| ALT onoff   { }
5033 	| MINP NUMBER   { }
5034 	| MAXP NUMBER   { }
5035 	| LOG onoff   { }
5036 	| TYPE AUTO {
5037 	    if (!is_valid_axis(whichgraph, naxis)) {
5038                 yyerror("No valid axis selected");
5039                 return 1;
5040             }
5041 	    g[whichgraph].t[naxis]->t_spec = TICKS_SPEC_NONE;
5042 	}
5043 	| TYPE SPEC {
5044 	    if (!is_valid_axis(whichgraph, naxis)) {
5045                 yyerror("No valid axis selected");
5046                 return 1;
5047             }
5048 	    if (g[whichgraph].t[naxis]->t_spec != TICKS_SPEC_BOTH) {
5049                 g[whichgraph].t[naxis]->t_spec = TICKS_SPEC_MARKS;
5050             }
5051 	}
5052 	| MINOR expr {
5053 	    if (!is_valid_axis(whichgraph, naxis)) {
5054                 yyerror("No valid axis selected");
5055                 return 1;
5056             }
5057 	    if ($2 != 0.0) {
5058                 g[whichgraph].t[naxis]->nminor =
5059                             (int) rint(g[whichgraph].t[naxis]->tmajor / $2 - 1);
5060             } else {
5061                 g[whichgraph].t[naxis]->nminor = 0;
5062             }
5063 	}
5064 	| SIZE expr {
5065 	    if (!is_valid_axis(whichgraph, naxis)) {
5066                 yyerror("No valid axis selected");
5067                 return 1;
5068             }
5069 	    g[whichgraph].t[naxis]->props.size = $2;
5070 	}
5071 	| nexpr ',' expr {
5072 	    if (!is_valid_axis(whichgraph, naxis)) {
5073                 yyerror("No valid axis selected");
5074                 return 1;
5075             }
5076 	    g[whichgraph].t[naxis]->tloc[$1].wtpos = $3;
5077 	    g[whichgraph].t[naxis]->tloc[$1].type = TICK_TYPE_MAJOR;
5078 	}
5079 	| opchoice_sel_obs {
5080 	    if (!is_valid_axis(whichgraph, naxis)) {
5081                 yyerror("No valid axis selected");
5082                 return 1;
5083             }
5084 	    g[whichgraph].t[naxis]->t_op = $1;
5085 	}
5086         ;
5087 
5088 ticklabelattr_obs:
5089 	linew_select { }
5090 	| TYPE AUTO {
5091 	    if (!is_valid_axis(whichgraph, naxis)) {
5092                 yyerror("No valid axis selected");
5093                 return 1;
5094             }
5095 	    if (g[whichgraph].t[naxis]->t_spec == TICKS_SPEC_BOTH) {
5096                 g[whichgraph].t[naxis]->t_spec = TICKS_SPEC_MARKS;
5097             }
5098 	}
5099 	| TYPE SPEC {
5100 	    if (!is_valid_axis(whichgraph, naxis)) {
5101                 yyerror("No valid axis selected");
5102                 return 1;
5103             }
5104 	    g[whichgraph].t[naxis]->t_spec = TICKS_SPEC_BOTH;
5105 	}
5106 	| LAYOUT SPEC { }
5107 
5108 	| LAYOUT HORIZONTAL {
5109 	    if (!is_valid_axis(whichgraph, naxis)) {
5110                 yyerror("No valid axis selected");
5111                 return 1;
5112             }
5113 	    g[whichgraph].t[naxis]->tl_angle = 0;
5114 	}
5115 	| LAYOUT VERTICAL {
5116 	    if (!is_valid_axis(whichgraph, naxis)) {
5117                 yyerror("No valid axis selected");
5118                 return 1;
5119             }
5120 	    g[whichgraph].t[naxis]->tl_angle = 90;
5121 	}
5122 	| PLACE ON TICKSP { }
5123 	| PLACE BETWEEN TICKSP { }
5124 	| opchoice_sel_obs {
5125 	    if (!is_valid_axis(whichgraph, naxis)) {
5126                 yyerror("No valid axis selected");
5127                 return 1;
5128             }
5129 	    g[whichgraph].t[naxis]->tl_op = $1;
5130 	}
5131 	| SIGN signchoice {
5132 	    if (!is_valid_axis(whichgraph, naxis)) {
5133                 yyerror("No valid axis selected");
5134                 return 1;
5135             }
5136 	    switch($2) {
5137             case SIGN_NEGATE:
5138                 g[whichgraph].t[naxis]->tl_formula =
5139                     copy_string(g[whichgraph].t[naxis]->tl_formula, "-$t");
5140                 break;
5141             case SIGN_ABSOLUTE:
5142                 g[whichgraph].t[naxis]->tl_formula =
5143                     copy_string(g[whichgraph].t[naxis]->tl_formula, "abs($t)");
5144                 break;
5145             default:
5146                 g[whichgraph].t[naxis]->tl_formula =
5147                     copy_string(g[whichgraph].t[naxis]->tl_formula, NULL);
5148                 break;
5149             }
5150 	}
5151         ;
5152 
5153 colpat_obs: NONE
5154 	| COLOR
5155 	| PATTERN
5156 	;
5157 
5158 opchoice_sel_obs: OP opchoice_obs
5159         {
5160             $$ = $2;
5161         }
5162         ;
5163 
5164 opchoice_obs: TOP { $$ = PLACEMENT_OPPOSITE; }
5165 	| BOTTOM { $$ = PLACEMENT_NORMAL; }
5166 	| LEFT { $$ = PLACEMENT_NORMAL; }
5167 	| RIGHT { $$ = PLACEMENT_OPPOSITE; }
5168 	| BOTH { $$ = PLACEMENT_BOTH; }
5169 	;
5170 
5171 %%
5172 
5173 /* list of intrinsic functions and keywords */
5174 symtab_entry ikey[] = {
5175 	{"A0", FITPARM, NULL},
5176 	{"A0MAX", FITPMAX, NULL},
5177 	{"A0MIN", FITPMIN, NULL},
5178 	{"A1", FITPARM, NULL},
5179 	{"A1MAX", FITPMAX, NULL},
5180 	{"A1MIN", FITPMIN, NULL},
5181 	{"A2", FITPARM, NULL},
5182 	{"A2MAX", FITPMAX, NULL},
5183 	{"A2MIN", FITPMIN, NULL},
5184 	{"A3", FITPARM, NULL},
5185 	{"A3MAX", FITPMAX, NULL},
5186 	{"A3MIN", FITPMIN, NULL},
5187 	{"A4", FITPARM, NULL},
5188 	{"A4MAX", FITPMAX, NULL},
5189 	{"A4MIN", FITPMIN, NULL},
5190 	{"A5", FITPARM, NULL},
5191 	{"A5MAX", FITPMAX, NULL},
5192 	{"A5MIN", FITPMIN, NULL},
5193 	{"A6", FITPARM, NULL},
5194 	{"A6MAX", FITPMAX, NULL},
5195 	{"A6MIN", FITPMIN, NULL},
5196 	{"A7", FITPARM, NULL},
5197 	{"A7MAX", FITPMAX, NULL},
5198 	{"A7MIN", FITPMIN, NULL},
5199 	{"A8", FITPARM, NULL},
5200 	{"A8MAX", FITPMAX, NULL},
5201 	{"A8MIN", FITPMIN, NULL},
5202 	{"A9", FITPARM, NULL},
5203 	{"A9MAX", FITPMAX, NULL},
5204 	{"A9MIN", FITPMIN, NULL},
5205 	{"ABOVE", ABOVE, NULL},
5206 	{"ABS", FUNC_D, (void *) fabs},
5207 	{"ABSOLUTE", ABSOLUTE, NULL},
5208 	{"ACOS", FUNC_D, (void *) acos},
5209 	{"ACOSH", FUNC_D, (void *) acosh},
5210 	{"AI", FUNC_D, (void *) ai_wrap},
5211 	{"ALIAS", ALIAS, NULL},
5212 	{"ALT", ALT, NULL},
5213 	{"ALTXAXIS", ALTXAXIS, NULL},
5214 	{"ALTYAXIS", ALTYAXIS, NULL},
5215 	{"AND", AND, NULL},
5216 	{"ANGLE", ANGLE, NULL},
5217 	{"ANTIALIASING", ANTIALIASING, NULL},
5218 	{"APPEND", APPEND, NULL},
5219 	{"ARRANGE", ARRANGE, NULL},
5220 	{"ARROW", ARROW, NULL},
5221 	{"ASCENDING", ASCENDING, NULL},
5222 	{"ASIN", FUNC_D, (void *) asin},
5223 	{"ASINH", FUNC_D, (void *) asinh},
5224 	{"ASPLINE", ASPLINE, NULL},
5225 	{"ATAN", FUNC_D, (void *) atan},
5226 	{"ATAN2", FUNC_DD, (void *) atan2},
5227 	{"ATANH", FUNC_D, (void *) atanh},
5228 	{"AUTO", AUTO, NULL},
5229 	{"AUTOSCALE", AUTOSCALE, NULL},
5230 	{"AUTOTICKS", AUTOTICKS, NULL},
5231 	{"AVALUE", AVALUE, NULL},
5232 	{"AVG", AVG, NULL},
5233 	{"BACKGROUND", BACKGROUND, NULL},
5234 	{"BAR", BAR, NULL},
5235 	{"BARDY", BARDY, NULL},
5236 	{"BARDYDY", BARDYDY, NULL},
5237 	{"BASELINE", BASELINE, NULL},
5238 	{"BATCH", BATCH, NULL},
5239         {"BEGIN", BEGIN, NULL},
5240 	{"BELOW", BELOW, NULL},
5241 	{"BETA", FUNC_DD, (void *) beta},
5242 	{"BETWEEN", BETWEEN, NULL},
5243 	{"BI", FUNC_D, (void *) bi_wrap},
5244 	{"BLACKMAN", BLACKMAN, NULL},
5245 	{"BLOCK", BLOCK, NULL},
5246 	{"BOTH", BOTH, NULL},
5247 	{"BOTTOM", BOTTOM, NULL},
5248 	{"BOX", BOX, NULL},
5249 	{"CD", CD, NULL},
5250 	{"CEIL", FUNC_D, (void *) ceil},
5251 	{"CENTER", CENTER, NULL},
5252 	{"CHAR", CHAR, NULL},
5253 	{"CHART", CHART, NULL},
5254 	{"CHDTR", FUNC_DD, (void *) chdtr},
5255 	{"CHDTRC", FUNC_DD, (void *) chdtrc},
5256 	{"CHDTRI", FUNC_DD, (void *) chdtri},
5257 	{"CHI", FUNC_D, (void *) chi_wrap},
5258 	{"CI", FUNC_D, (void *) ci_wrap},
5259 	{"CLEAR", CLEAR, NULL},
5260 	{"CLICK", CLICK, NULL},
5261 	{"CLIP", CLIP, NULL},
5262 	{"CLOSE", CLOSE, NULL},
5263 	{"COEFFICIENTS", COEFFICIENTS, NULL},
5264 	{"COLOR", COLOR, NULL},
5265 	{"COMMENT", COMMENT, NULL},
5266 	{"COMPLEX", COMPLEX, NULL},
5267 	{"COMPUTING", COMPUTING, NULL},
5268 	{"CONST", KEY_CONST, NULL},
5269 	{"CONSTRAINTS", CONSTRAINTS, NULL},
5270 	{"COPY", COPY, NULL},
5271 	{"COS", FUNC_D, (void *) cos},
5272 	{"COSH", FUNC_D, (void *) cosh},
5273 	{"CYCLE", CYCLE, NULL},
5274 	{"DATE", DATE, NULL},
5275 	{"DAWSN", FUNC_D, (void *) dawsn},
5276 	{"DAYMONTH", DAYMONTH, NULL},
5277 	{"DAYOFWEEKL", DAYOFWEEKL, NULL},
5278 	{"DAYOFWEEKS", DAYOFWEEKS, NULL},
5279 	{"DAYOFYEAR", DAYOFYEAR, NULL},
5280 	{"DDMMYY", DDMMYY, NULL},
5281 	{"DECIMAL", DECIMAL, NULL},
5282 	{"DEF", DEF, NULL},
5283 	{"DEFAULT", DEFAULT, NULL},
5284 	{"DEFINE", DEFINE, NULL},
5285 	{"DEG", UCONSTANT, (void *) deg_uconst},
5286 	{"DEGREESLAT", DEGREESLAT, NULL},
5287 	{"DEGREESLON", DEGREESLON, NULL},
5288 	{"DEGREESMMLAT", DEGREESMMLAT, NULL},
5289 	{"DEGREESMMLON", DEGREESMMLON, NULL},
5290 	{"DEGREESMMSSLAT", DEGREESMMSSLAT, NULL},
5291 	{"DEGREESMMSSLON", DEGREESMMSSLON, NULL},
5292 	{"DESCENDING", DESCENDING, NULL},
5293 	{"DESCRIPTION", DESCRIPTION, NULL},
5294 	{"DEVICE", DEVICE, NULL},
5295 	{"DFT", DFT, NULL},
5296 	{"DIFF", DIFFERENCE, NULL},
5297 	{"DIFFERENCE", DIFFERENCE, NULL},
5298 	{"DISK", DISK, NULL},
5299 	{"DOWN", DOWN, NULL},
5300 	{"DPI", DPI, NULL},
5301 	{"DROP", DROP, NULL},
5302 	{"DROPLINE", DROPLINE, NULL},
5303 	{"ECHO", ECHO, NULL},
5304 	{"ELLIE", FUNC_DD, (void *) ellie},
5305 	{"ELLIK", FUNC_DD, (void *) ellik},
5306 	{"ELLIPSE", ELLIPSE, NULL},
5307 	{"ELLPE", FUNC_D, (void *) ellpe_wrap},
5308 	{"ELLPK", FUNC_D, (void *) ellpk_wrap},
5309 	{"ENGINEERING", ENGINEERING, NULL},
5310 	{"EQ", EQ, NULL},
5311 	{"ER", ERRORBAR, NULL},
5312 	{"ERF", FUNC_D, (void *) erf},
5313 	{"ERFC", FUNC_D, (void *) erfc},
5314 	{"ERRORBAR", ERRORBAR, NULL},
5315 	{"EXIT", EXIT, NULL},
5316 	{"EXP", FUNC_D, (void *) exp},
5317 	{"EXPN", FUNC_ND, (void *) expn},
5318 	{"EXPONENTIAL", EXPONENTIAL, NULL},
5319 	{"FAC", FUNC_I, (void *) fac},
5320 	{"FALSE", OFF, NULL},
5321 	{"FDTR", FUNC_NND, (void *) fdtr},
5322 	{"FDTRC", FUNC_NND, (void *) fdtrc},
5323 	{"FDTRI", FUNC_NND, (void *) fdtri},
5324 	{"FFT", FFT, NULL},
5325 	{"FILE", FILEP, NULL},
5326 	{"FILL", FILL, NULL},
5327 	{"FIT", FIT, NULL},
5328 	{"FIXED", FIXED, NULL},
5329 	{"FIXEDPOINT", FIXEDPOINT, NULL},
5330 	{"FLOOR", FUNC_D, (void *) floor},
5331 	{"FLUSH", FLUSH, NULL},
5332 	{"FOCUS", FOCUS, NULL},
5333 	{"FOLLOWS", FOLLOWS, NULL},
5334 	{"FONT", FONTP, NULL},
5335 	{"FORCE", FORCE, NULL},
5336 	{"FORMAT", FORMAT, NULL},
5337 	{"FORMULA", FORMULA, NULL},
5338 	{"FRAME", FRAMEP, NULL},
5339 	{"FREE", FREE, NULL},
5340 	{"FREQUENCY", FREQUENCY, NULL},
5341 	{"FRESNLC", FUNC_D, (void *) fresnlc_wrap},
5342 	{"FRESNLS", FUNC_D, (void *) fresnls_wrap},
5343 	{"FROM", FROM, NULL},
5344 	{"F_OF_D", KEY_FUNC_D, NULL},
5345 	{"F_OF_DD", KEY_FUNC_DD, NULL},
5346         {"F_OF_I", KEY_FUNC_I, NULL},
5347 	{"F_OF_ND", KEY_FUNC_ND, NULL},
5348 	{"F_OF_NN", KEY_FUNC_NN, NULL},
5349 	{"F_OF_NND", KEY_FUNC_NND, NULL},
5350 	{"F_OF_PPD", KEY_FUNC_PPD, NULL},
5351 	{"F_OF_PPPD", KEY_FUNC_PPPD, NULL},
5352 	{"F_OF_PPPPD", KEY_FUNC_PPPPD, NULL},
5353 	{"F_OF_PPPPPD", KEY_FUNC_PPPPPD, NULL},
5354 	{"GAMMA", FUNC_D, (void *) true_gamma},
5355 	{"GDTR", FUNC_PPD, (void *) gdtr},
5356 	{"GDTRC", FUNC_PPD, (void *) gdtrc},
5357 	{"GE", GE, NULL},
5358 	{"GENERAL", GENERAL, NULL},
5359 	{"GETP", GETP, NULL},
5360 	{"GRAPH", GRAPH, NULL},
5361 	{"GRID", GRID, NULL},
5362 	{"GT", GT, NULL},
5363 	{"HAMMING", HAMMING, NULL},
5364 	{"HANNING", HANNING, NULL},
5365 	{"HARDCOPY", HARDCOPY, NULL},
5366 	{"HBAR", HBAR, NULL},
5367 	{"HELP", HELP, NULL},
5368 	{"HGAP", HGAP, NULL},
5369 	{"HIDDEN", HIDDEN, NULL},
5370 	{"HISTOGRAM", HISTOGRAM, NULL},
5371 	{"HMS", HMS, NULL},
5372 	{"HORIZI", HORIZI, NULL},
5373 	{"HORIZO", HORIZO, NULL},
5374 	{"HORIZONTAL", HORIZONTAL, NULL},
5375 	{"HYP2F1", FUNC_PPPD, (void *) hyp2f1},
5376 	{"HYPERG", FUNC_PPD, (void *) hyperg},
5377 	{"HYPOT", FUNC_DD, (void *) hypot},
5378 	{"I0E", FUNC_D, (void *) i0e},
5379 	{"I1E", FUNC_D, (void *) i1e},
5380 	{"ID", ID, NULL},
5381 	{"IFILTER", IFILTER, NULL},
5382 	{"IGAM", FUNC_DD, (void *) igam},
5383 	{"IGAMC", FUNC_DD, (void *) igamc},
5384 	{"IGAMI", FUNC_DD, (void *) igami},
5385 	{"IMAX", IMAX, NULL},
5386 	{"IMIN", IMIN, NULL},
5387 	{"IN", IN, NULL},
5388 	{"INCBET", FUNC_PPD, (void *) incbet},
5389 	{"INCBI", FUNC_PPD, (void *) incbi},
5390 	{"INCREMENT", INCREMENT, NULL},
5391 	{"INDEX", INDEX, NULL},
5392 	{"INOUT", INOUT, NULL},
5393 	{"INT", INT, NULL},
5394 	{"INTEGRATE", INTEGRATE, NULL},
5395 	{"INTERPOLATE", INTERPOLATE, NULL},
5396 	{"INVDFT", INVDFT, NULL},
5397 	{"INVERT", INVERT, NULL},
5398 	{"INVFFT", INVFFT, NULL},
5399 	{"IRAND", FUNC_I, (void *) irand_wrap},
5400 	{"IV", FUNC_DD, (void *) iv_wrap},
5401 	{"JUST", JUST, NULL},
5402 	{"JV", FUNC_DD, (void *) jv_wrap},
5403 	{"K0E", FUNC_D, (void *) k0e},
5404 	{"K1E", FUNC_D, (void *) k1e},
5405 	{"KILL", KILL, NULL},
5406 	{"KN", FUNC_ND, (void *) kn_wrap},
5407 	{"LABEL", LABEL, NULL},
5408 	{"LANDSCAPE", LANDSCAPE, NULL},
5409 	{"LAYOUT", LAYOUT, NULL},
5410 	{"LBETA", FUNC_DD, (void *) lbeta},
5411 	{"LE", LE, NULL},
5412 	{"LEFT", LEFT, NULL},
5413 	{"LEGEND", LEGEND, NULL},
5414 	{"LENGTH", LENGTH, NULL},
5415 	{"LGAMMA", FUNC_D, (void *) lgamma},
5416 	{"LINCONV", LINCONV, NULL},
5417 	{"LINE", LINE, NULL},
5418 	{"LINEAR", LINEAR, NULL},
5419 	{"LINESTYLE", LINESTYLE, NULL},
5420 	{"LINEWIDTH", LINEWIDTH, NULL},
5421 	{"LINK", LINK, NULL},
5422 	{"LN", FUNC_D, (void *) log},
5423 	{"LOAD", LOAD, NULL},
5424 	{"LOCTYPE", LOCTYPE, NULL},
5425 	{"LOG", LOG, NULL},
5426 	{"LOG10", FUNC_D, (void *) log10},
5427 	{"LOG2", FUNC_D, (void *) log2},
5428 	{"LOGARITHMIC", LOGARITHMIC, NULL},
5429 	{"LOGX", LOGX, NULL},
5430 	{"LOGXY", LOGXY, NULL},
5431 	{"LOGY", LOGY, NULL},
5432 	{"LOGIT", LOGIT, NULL},
5433 	{"LT", LT, NULL},
5434 	{"MAGIC", MAGIC, NULL},
5435 	{"MAGNITUDE", MAGNITUDE, NULL},
5436 	{"MAJOR", MAJOR, NULL},
5437 	{"MAP", MAP, NULL},
5438 	{"MAX", MAXP, NULL},
5439 	{"MAXOF", FUNC_DD, (void *) max_wrap},
5440 	{"MESH", MESH, NULL},
5441 	{"MIN", MINP, NULL},
5442 	{"MINOF", FUNC_DD, (void *) min_wrap},
5443 	{"MINOR", MINOR, NULL},
5444 	{"MMDD", MMDD, NULL},
5445 	{"MMDDHMS", MMDDHMS, NULL},
5446 	{"MMDDYY", MMDDYY, NULL},
5447 	{"MMDDYYHMS", MMDDYYHMS, NULL},
5448 	{"MMSSLAT", MMSSLAT, NULL},
5449 	{"MMSSLON", MMSSLON, NULL},
5450 	{"MMYY", MMYY, NULL},
5451 	{"MOD", FUNC_DD, (void *) fmod},
5452 	{"MONTHDAY", MONTHDAY, NULL},
5453 	{"MONTHL", MONTHL, NULL},
5454 	{"MONTHS", MONTHS, NULL},
5455 	{"MONTHSY", MONTHSY, NULL},
5456 	{"MOVE", MOVE, NULL},
5457 	{"NDTR", FUNC_D, (void *) ndtr},
5458 	{"NDTRI", FUNC_D, (void *) ndtri},
5459 	{"NE", NE, NULL},
5460 	{"NEGATE", NEGATE, NULL},
5461 	{"NEW", NEW, NULL},
5462 	{"NONE", NONE, NULL},
5463 	{"NONLFIT", NONLFIT, NULL},
5464 	{"NORM", FUNC_D, (void *) fx},
5465 	{"NORMAL", NORMAL, NULL},
5466 	{"NOT", NOT, NULL},
5467 	{"NXY", NXY, NULL},
5468 	{"OFF", OFF, NULL},
5469 	{"OFFSET", OFFSET, NULL},
5470 	{"OFFSETX", OFFSETX, NULL},
5471 	{"OFFSETY", OFFSETY, NULL},
5472 	{"OFILTER", OFILTER, NULL},
5473 	{"ON", ON, NULL},
5474 	{"ONREAD", ONREAD, NULL},
5475 	{"OP", OP, NULL},
5476 	{"OPPOSITE", OPPOSITE, NULL},
5477 	{"OR", OR, NULL},
5478 	{"OUT", OUT, NULL},
5479 	{"PAGE", PAGE, NULL},
5480 	{"PARA", PARA, NULL},
5481 	{"PARAMETERS", PARAMETERS, NULL},
5482 	{"PARZEN", PARZEN, NULL},
5483 	{"PATTERN", PATTERN, NULL},
5484 	{"PDTR", FUNC_ND, (void *) pdtr},
5485 	{"PDTRC", FUNC_ND, (void *) pdtrc},
5486 	{"PDTRI", FUNC_ND, (void *) pdtri},
5487 	{"PERIOD", PERIOD, NULL},
5488 	{"PERP", PERP, NULL},
5489 	{"PHASE", PHASE, NULL},
5490 	{"PI", CONSTANT, (void *) pi_const},
5491 	{"PIE", PIE, NULL},
5492 	{"PIPE", PIPE, NULL},
5493 	{"PLACE", PLACE, NULL},
5494 	{"POINT", POINT, NULL},
5495 	{"POLAR", POLAR, NULL},
5496 	{"POLYI", POLYI, NULL},
5497 	{"POLYO", POLYO, NULL},
5498 	{"POP", POP, NULL},
5499 	{"PORTRAIT", PORTRAIT, NULL},
5500 	{"POWER", POWER, NULL},
5501 	{"PREC", PREC, NULL},
5502 	{"PREPEND", PREPEND, NULL},
5503 	{"PRINT", PRINT, NULL},
5504 	{"PS", PS, NULL},
5505 	{"PSI", FUNC_D, (void *) psi},
5506 	{"PUSH", PUSH, NULL},
5507 	{"PUTP", PUTP, NULL},
5508 	{"RAD", UCONSTANT, (void *) rad_uconst},
5509 	{"RAND", RAND, NULL},
5510 	{"READ", READ, NULL},
5511 	{"REAL", REAL, NULL},
5512 	{"RECIPROCAL", RECIPROCAL, NULL},
5513 	{"REDRAW", REDRAW, NULL},
5514 	{"REFERENCE", REFERENCE, NULL},
5515 	{"REGRESS", REGRESS, NULL},
5516 	{"RESIZE", RESIZE, NULL},
5517 	{"RESTRICT", RESTRICT, NULL},
5518 	{"REVERSE", REVERSE, NULL},
5519 	{"RGAMMA", FUNC_D, (void *) rgamma},
5520 	{"RIGHT", RIGHT, NULL},
5521 	{"RINT", FUNC_D, (void *) rint},
5522 	{"RISER", RISER, NULL},
5523 	{"RNORM", FUNC_DD, (void *) rnorm},
5524 	{"ROT", ROT, NULL},
5525 	{"ROUNDED", ROUNDED, NULL},
5526 	{"RSUM", RSUM, NULL},
5527 	{"RULE", RULE, NULL},
5528 	{"RUNAVG", RUNAVG, NULL},
5529 	{"RUNMAX", RUNMAX, NULL},
5530 	{"RUNMED", RUNMED, NULL},
5531 	{"RUNMIN", RUNMIN, NULL},
5532 	{"RUNSTD", RUNSTD, NULL},
5533 	{"SAVEALL", SAVEALL, NULL},
5534 	{"SCALE", SCALE, NULL},
5535 	{"SCIENTIFIC", SCIENTIFIC, NULL},
5536 	{"SCROLL", SCROLL, NULL},
5537 	{"SD", SD, NULL},
5538 	{"SET", SET, NULL},
5539 	{"SFORMAT", SFORMAT, NULL},
5540 	{"SGN", FUNC_D, (void *) sign_wrap},
5541 	{"SHI", FUNC_D, (void *) shi_wrap},
5542 	{"SI", FUNC_D, (void *) si_wrap},
5543 	{"SIGN", SIGN, NULL},
5544 	{"SIN", FUNC_D, (void *) sin},
5545 	{"SINH", FUNC_D, (void *) sinh},
5546 	{"SIZE", SIZE, NULL},
5547 	{"SKIP", SKIP, NULL},
5548 	{"SLEEP", SLEEP, NULL},
5549 	{"SMITH", SMITH, NULL},
5550 	{"SORT", SORT, NULL},
5551 	{"SOURCE", SOURCE, NULL},
5552 	{"SPEC", SPEC, NULL},
5553 	{"SPENCE", FUNC_D, (void *) spence},
5554 	{"SPLINE", SPLINE, NULL},
5555 	{"SPLIT", SPLIT, NULL},
5556 	{"SQR", FUNC_D, (void *) sqr_wrap},
5557 	{"SQRT", FUNC_D, (void *) sqrt},
5558 	{"STACK", STACK, NULL},
5559 	{"STACKED", STACKED, NULL},
5560 	{"STACKEDBAR", STACKEDBAR, NULL},
5561 	{"STACKEDHBAR", STACKEDHBAR, NULL},
5562 	{"STAGGER", STAGGER, NULL},
5563 	{"START", START, NULL},
5564 	{"STDTR", FUNC_ND, (void *) stdtr},
5565 	{"STDTRI", FUNC_ND, (void *) stdtri},
5566 	{"STOP", STOP, NULL},
5567 	{"STRING", STRING, NULL},
5568 	{"STRUVE", FUNC_DD, (void *) struve},
5569 	{"SUBTITLE", SUBTITLE, NULL},
5570 	{"SUM", SUM, NULL},
5571 	{"SWAP", SWAP, NULL},
5572 	{"SYMBOL", SYMBOL, NULL},
5573 	{"TAN", FUNC_D, (void *) tan},
5574 	{"TANH", FUNC_D, (void *) tanh},
5575 	{"TARGET", TARGET, NULL},
5576 	{"TICK", TICKP, NULL},
5577 	{"TICKLABEL", TICKLABEL, NULL},
5578 	{"TICKS", TICKSP, NULL},
5579 	{"TIMER", TIMER, NULL},
5580 	{"TIMESTAMP", TIMESTAMP, NULL},
5581 	{"TITLE", TITLE, NULL},
5582 	{"TO", TO, NULL},
5583 	{"TOP", TOP, NULL},
5584 	{"TRIANGULAR", TRIANGULAR, NULL},
5585 	{"TRUE", ON, NULL},
5586 	{"TYPE", TYPE, NULL},
5587 	{"UNIT", KEY_UNIT, NULL},
5588 	{"UP", UP, NULL},
5589 	{"UPDATEALL", UPDATEALL, NULL},
5590 	{"USE", USE, NULL},
5591 	{"VERSION", VERSION, NULL},
5592 	{"VERTI", VERTI, NULL},
5593 	{"VERTICAL", VERTICAL, NULL},
5594 	{"VERTO", VERTO, NULL},
5595 	{"VGAP", VGAP, NULL},
5596 	{"VIEW", VIEW, NULL},
5597 	{"VOIGT", FUNC_PPD, (void *) voigt},
5598 	{"VX1", VX1, NULL},
5599 	{"VX2", VX2, NULL},
5600 	{"VXMAX", VXMAX, NULL},
5601 	{"VY1", VY1, NULL},
5602 	{"VY2", VY2, NULL},
5603 	{"VYMAX", VYMAX, NULL},
5604 	{"WELCH", WELCH, NULL},
5605 	{"WITH", WITH, NULL},
5606 	{"WORLD", WORLD, NULL},
5607 	{"WRAP", WRAP, NULL},
5608 	{"WRITE", WRITE, NULL},
5609 	{"WX1", WX1, NULL},
5610 	{"WX2", WX2, NULL},
5611 	{"WY1", WY1, NULL},
5612 	{"WY2", WY2, NULL},
5613 	{"X", X_TOK, NULL},
5614 	{"X0", X0, NULL},
5615 	{"X1", X1, NULL},
5616 	{"XAXES", XAXES, NULL},
5617 	{"XAXIS", XAXIS, NULL},
5618 	{"XCOR", XCOR, NULL},
5619 	{"XMAX", XMAX, NULL},
5620 	{"XMIN", XMIN, NULL},
5621 	{"XY", XY, NULL},
5622 	{"XYAXES", XYAXES, NULL},
5623 	{"XYBOXPLOT", XYBOXPLOT, NULL},
5624 	{"XYCOLOR", XYCOLOR, NULL},
5625 	{"XYCOLPAT", XYCOLPAT, NULL},
5626 	{"XYDX", XYDX, NULL},
5627 	{"XYDXDX", XYDXDX, NULL},
5628 	{"XYDXDXDYDY", XYDXDXDYDY, NULL},
5629 	{"XYDXDY", XYDXDY, NULL},
5630 	{"XYDY", XYDY, NULL},
5631 	{"XYDYDY", XYDYDY, NULL},
5632 	{"XYHILO", XYHILO, NULL},
5633 	{"XYR", XYR, NULL},
5634 	{"XYSIZE", XYSIZE, NULL},
5635 	{"XYSTRING", XYSTRING, NULL},
5636 	{"XYVMAP", XYVMAP, NULL},
5637 	{"XYZ", XYZ, NULL},
5638 	{"Y", Y_TOK, NULL},
5639 	{"Y0", Y0, NULL},
5640 	{"Y1", Y1, NULL},
5641 	{"Y2", Y2, NULL},
5642 	{"Y3", Y3, NULL},
5643 	{"Y4", Y4, NULL},
5644 	{"YAXES", YAXES, NULL},
5645 	{"YAXIS", YAXIS, NULL},
5646 	{"YEAR", YEAR, NULL},
5647 	{"YMAX", YMAX, NULL},
5648 	{"YMIN", YMIN, NULL},
5649 	{"YV", FUNC_DD, (void *) yv_wrap},
5650 	{"YYMMDD", YYMMDD, NULL},
5651 	{"YYMMDDHMS", YYMMDDHMS, NULL},
5652 	{"ZERO", ZERO, NULL},
5653 	{"ZEROXAXIS", ALTXAXIS, NULL},
5654 	{"ZEROYAXIS", ALTYAXIS, NULL},
5655 	{"ZETA", FUNC_DD, (void *) zeta},
5656 	{"ZETAC", FUNC_D, (void *) zetac},
5657 	{"ZNORM", ZNORM, NULL}
5658 };
5659 
5660 static int maxfunc = sizeof(ikey) / sizeof(symtab_entry);
5661 
get_parser_gno(void)5662 int get_parser_gno(void)
5663 {
5664     return whichgraph;
5665 }
5666 
set_parser_gno(int gno)5667 int set_parser_gno(int gno)
5668 {
5669     if (is_valid_gno(gno) == TRUE) {
5670         whichgraph = gno;
5671         return RETURN_SUCCESS;
5672     } else {
5673         return RETURN_FAILURE;
5674     }
5675 }
5676 
get_parser_setno(void)5677 int get_parser_setno(void)
5678 {
5679     return whichset;
5680 }
5681 
set_parser_setno(int gno,int setno)5682 int set_parser_setno(int gno, int setno)
5683 {
5684     if (is_valid_setno(gno, setno) == TRUE) {
5685         whichgraph = gno;
5686         whichset = setno;
5687         /* those will usually be overridden except when evaluating
5688            a _standalone_ vexpr */
5689         vasgn_gno = gno;
5690         vasgn_setno = setno;
5691         return RETURN_SUCCESS;
5692     } else {
5693         return RETURN_FAILURE;
5694     }
5695 }
5696 
realloc_vrbl(grarr * vrbl,int len)5697 void realloc_vrbl(grarr *vrbl, int len)
5698 {
5699     double *a;
5700     int i, oldlen;
5701 
5702     if (vrbl->type != GRARR_VEC) {
5703         errmsg("Internal error");
5704         return;
5705     }
5706     oldlen = vrbl->length;
5707     if (oldlen == len) {
5708         return;
5709     } else {
5710         a = xrealloc(vrbl->data, len*SIZEOF_DOUBLE);
5711         if (a != NULL || len == 0) {
5712             vrbl->data = a;
5713             vrbl->length = len;
5714             for (i = oldlen; i < len; i++) {
5715                 vrbl->data[i] = 0.0;
5716             }
5717         } else {
5718             errmsg("Malloc failed in realloc_vrbl()");
5719         }
5720     }
5721 }
5722 
5723 
5724 #define PARSER_TYPE_VOID    0
5725 #define PARSER_TYPE_EXPR    1
5726 #define PARSER_TYPE_VEXPR   2
5727 
parser(char * s,int type)5728 static int parser(char *s, int type)
5729 {
5730     char *seekpos;
5731     int i;
5732 
5733     if (s == NULL || s[0] == '\0') {
5734         if (type == PARSER_TYPE_VOID) {
5735             /* don't consider an empty string as error for generic parser */
5736             return RETURN_SUCCESS;
5737         } else {
5738             return RETURN_FAILURE;
5739         }
5740     }
5741 
5742     strncpy(f_string, s, MAX_PARS_STRING_LENGTH - 2);
5743     f_string[MAX_PARS_STRING_LENGTH - 2] = '\0';
5744     strcat(f_string, " ");
5745 
5746     seekpos = f_string;
5747 
5748     while ((seekpos - f_string < MAX_PARS_STRING_LENGTH - 1) && (*seekpos == ' ' || *seekpos == '\t')) {
5749         seekpos++;
5750     }
5751     if (*seekpos == '\n' || *seekpos == '#') {
5752         if (type == PARSER_TYPE_VOID) {
5753             /* don't consider an empty string as error for generic parser */
5754             return RETURN_SUCCESS;
5755         } else {
5756             return RETURN_FAILURE;
5757         }
5758     }
5759 
5760     lowtoupper(f_string);
5761 
5762     pos = 0;
5763     interr = 0;
5764     expr_parsed  = FALSE;
5765     vexpr_parsed = FALSE;
5766 
5767     yyparse();
5768 
5769     /* free temp. arrays; for a vector expression keep the last one
5770      * (which is none but v_result), given there have been no errors
5771      * and it's what we've been asked for
5772      */
5773     if (vexpr_parsed && !interr && type == PARSER_TYPE_VEXPR) {
5774         for (i = 0; i < fcnt - 1; i++) {
5775             free_tmpvrbl(&(freelist[i]));
5776         }
5777     } else {
5778         for (i = 0; i < fcnt; i++) {
5779             free_tmpvrbl(&(freelist[i]));
5780         }
5781     }
5782     fcnt = 0;
5783 
5784     tgtn = 0;
5785 
5786     if ((type == PARSER_TYPE_VEXPR && !vexpr_parsed) ||
5787         (type == PARSER_TYPE_EXPR  && !expr_parsed)) {
5788         return RETURN_FAILURE;
5789     } else {
5790         return (interr ? RETURN_FAILURE:RETURN_SUCCESS);
5791     }
5792 }
5793 
s_scanner(char * s,double * res)5794 int s_scanner(char *s, double *res)
5795 {
5796     int retval = parser(s, PARSER_TYPE_EXPR);
5797     *res = s_result;
5798     return retval;
5799 }
5800 
v_scanner(char * s,int * reslen,double ** vres)5801 int v_scanner(char *s, int *reslen, double **vres)
5802 {
5803     int retval = parser(s, PARSER_TYPE_VEXPR);
5804     if (retval != RETURN_SUCCESS) {
5805         return RETURN_FAILURE;
5806     } else {
5807         *reslen = v_result->length;
5808         if (v_result->type == GRARR_TMP) {
5809             *vres = v_result->data;
5810             v_result->length = 0;
5811             v_result->data = NULL;
5812         } else {
5813             *vres = copy_data_column(v_result->data, v_result->length);
5814         }
5815         return RETURN_SUCCESS;
5816     }
5817 }
5818 
scanner(char * s)5819 int scanner(char *s)
5820 {
5821     int retval = parser(s, PARSER_TYPE_VOID);
5822     if (retval != RETURN_SUCCESS) {
5823         return RETURN_FAILURE;
5824     }
5825 
5826     if (gotparams) {
5827 	gotparams = FALSE;
5828         getparms(paramfile);
5829     }
5830 
5831     if (gotread) {
5832 	gotread = FALSE;
5833         getdata(whichgraph, readfile, cursource, LOAD_SINGLE);
5834     }
5835 
5836     if (gotnlfit) {
5837 	gotnlfit = FALSE;
5838         do_nonlfit(nlfit_gno, nlfit_setno, nlfit_warray, NULL, nlfit_nsteps);
5839         XCFREE(nlfit_warray);
5840     }
5841     return retval;
5842 }
5843 
free_tmpvrbl(grarr * vrbl)5844 static void free_tmpvrbl(grarr *vrbl)
5845 {
5846     if (vrbl->type == GRARR_TMP) {
5847         vrbl->length = 0;
5848         XCFREE(vrbl->data);
5849     }
5850 }
5851 
copy_vrbl(grarr * dest,grarr * src)5852 static void copy_vrbl(grarr *dest, grarr *src)
5853 {
5854     dest->type = src->type;
5855     dest->data = xmalloc(src->length*SIZEOF_DOUBLE);
5856     if (dest->data == NULL) {
5857         errmsg("Malloc failed in copy_vrbl()");
5858     } else {
5859         memcpy(dest->data, src->data, src->length*SIZEOF_DOUBLE);
5860         dest->length = src->length;
5861     }
5862 }
5863 
get_parser_arr_by_name(char * const name)5864 grarr *get_parser_arr_by_name(char * const name)
5865 {
5866      int position;
5867      char *s;
5868 
5869      s = copy_string(NULL, name);
5870      lowtoupper(s);
5871 
5872      position = findf(key, s);
5873      xfree(s);
5874 
5875      if (position >= 0) {
5876          if (key[position].type == KEY_VEC) {
5877             return (grarr *) key[position].data;
5878          }
5879      }
5880 
5881      return NULL;
5882 }
5883 
define_parser_arr(char * const name)5884 grarr *define_parser_arr(char * const name)
5885 {
5886      if (get_parser_arr_by_name(name) == NULL) {
5887 	symtab_entry tmpkey;
5888         grarr *var;
5889 
5890         var = xmalloc(sizeof(grarr));
5891         var->type = GRARR_VEC;
5892         var->length = 0;
5893         var->data = NULL;
5894 
5895 	tmpkey.s = name;
5896 	tmpkey.type = KEY_VEC;
5897 	tmpkey.data = (void *) var;
5898 	if (addto_symtab(tmpkey) == RETURN_SUCCESS) {
5899 	    return var;
5900 	} else {
5901             return NULL;
5902         }
5903      } else {
5904         return NULL;
5905      }
5906 }
5907 
undefine_parser_var(void * ptr)5908 int undefine_parser_var(void *ptr)
5909 {
5910     int i;
5911 
5912     for (i = 0; i < maxfunc; i++) {
5913 	if (key[i].data == ptr) {
5914             xfree(key[i].s);
5915             maxfunc--;
5916             if (i != maxfunc) {
5917                 memmove(&(key[i]), &(key[i + 1]), (maxfunc - i)*sizeof(symtab_entry));
5918             }
5919             key = xrealloc(key, maxfunc*sizeof(symtab_entry));
5920             return RETURN_SUCCESS;
5921         }
5922     }
5923     return RETURN_FAILURE;
5924 }
5925 
find_set_bydata(double * data,target * tgt)5926 static int find_set_bydata(double *data, target *tgt)
5927 {
5928     int gno, setno, ncol;
5929 
5930     if (data == NULL) {
5931         return RETURN_FAILURE;
5932     } else {
5933         for (gno = 0; gno < number_of_graphs(); gno++) {
5934             for (setno = 0; setno < number_of_sets(gno); setno++) {
5935                 for (ncol = 0; ncol < MAX_SET_COLS; ncol++) {
5936                     if (getcol(gno, setno, ncol) == data) {
5937                         tgt->gno   = gno;
5938                         tgt->setno = setno;
5939                         return RETURN_SUCCESS;
5940                     }
5941                 }
5942             }
5943         }
5944     }
5945     return RETURN_FAILURE;
5946 }
5947 
findf(symtab_entry * keytable,char * s)5948 static int findf(symtab_entry *keytable, char *s)
5949 {
5950 
5951     int low, high, mid;
5952 
5953     low = 0;
5954     high = maxfunc - 1;
5955     while (low <= high) {
5956 	mid = (low + high) / 2;
5957 	if (strcmp(s, keytable[mid].s) < 0) {
5958 	    high = mid - 1;
5959 	} else {
5960 	    if (strcmp(s, keytable[mid].s) > 0) {
5961 		low = mid + 1;
5962 	    } else {
5963 		return (mid);
5964 	    }
5965 	}
5966     }
5967     return (-1);
5968 }
5969 
compare_keys(const void * a,const void * b)5970 static int compare_keys (const void *a, const void *b)
5971 {
5972     return (int) strcmp (((const symtab_entry*)a)->s,
5973                          ((const symtab_entry*)b)->s);
5974 }
5975 
5976 /* add new entry to the symbol table */
addto_symtab(symtab_entry newkey)5977 int addto_symtab(symtab_entry newkey)
5978 {
5979     int position;
5980     char *s;
5981 
5982     s = copy_string(NULL, newkey.s);
5983     lowtoupper(s);
5984     if ((position = findf(key, s)) < 0) {
5985         if ((key = (symtab_entry *) xrealloc(key, (maxfunc + 1)*sizeof(symtab_entry))) != NULL) {
5986 	    key[maxfunc].type = newkey.type;
5987 	    key[maxfunc].data = newkey.data;
5988 	    key[maxfunc].s = s;
5989 	    maxfunc++;
5990 	    qsort(key, maxfunc, sizeof(symtab_entry), compare_keys);
5991 	    return RETURN_SUCCESS;
5992 	} else {
5993 	    xfree(s);
5994 	    return RETURN_FAILURE;
5995 	}
5996     } else if (alias_force == TRUE) { /* already exists but alias_force enabled */
5997         key[position].type = newkey.type;
5998 	key[position].data = newkey.data;
5999 	return RETURN_SUCCESS;
6000     } else {
6001 	xfree(s);
6002         return RETURN_FAILURE;
6003     }
6004 }
6005 
6006 /* initialize symbol table */
init_symtab(void)6007 void init_symtab(void)
6008 {
6009     int i;
6010 
6011     if ((key = (symtab_entry *) xmalloc(maxfunc*sizeof(symtab_entry))) != NULL) {
6012     	memcpy (key, ikey, maxfunc*sizeof(symtab_entry));
6013 	for (i = 0; i < maxfunc; i++) {
6014 	    key[i].s = xmalloc(strlen(ikey[i].s) + 1);
6015 	    strcpy(key[i].s, ikey[i].s);
6016 	}
6017 	qsort(key, maxfunc, sizeof(symtab_entry), compare_keys);
6018 	return;
6019     } else {
6020 	key = ikey;
6021 	return;
6022     }
6023 }
6024 
getcharstr(void)6025 static int getcharstr(void)
6026 {
6027     if (pos >= strlen(f_string))
6028 	 return EOF;
6029     return (f_string[pos++]);
6030 }
6031 
ungetchstr(void)6032 static void ungetchstr(void)
6033 {
6034     if (pos > 0)
6035 	pos--;
6036 }
6037 
yylex(void)6038 static int yylex(void)
6039 {
6040     int c, i;
6041     int found;
6042     char sbuf[MAX_PARS_STRING_LENGTH + 40];
6043 
6044     while ((c = getcharstr()) == ' ' || c == '\t');
6045     if (c == EOF) {
6046 	return (0);
6047     }
6048     if (c == '"') {
6049 	i = 0;
6050 	while ((c = getcharstr()) != '"' && c != EOF) {
6051 	    if (c == '\\') {
6052 		int ctmp;
6053 		ctmp = getcharstr();
6054 		if (ctmp != '"') {
6055 		    ungetchstr();
6056 		}
6057 		else {
6058 		    c = ctmp;
6059 		}
6060 	    }
6061 	    sbuf[i] = c;
6062 	    i++;
6063 	}
6064 	if (c == EOF) {
6065 	    yyerror("Nonterminating string");
6066 	    return 0;
6067 	}
6068 	sbuf[i] = '\0';
6069 	yylval.sval = copy_string(NULL, sbuf);
6070 	return CHRSTR;
6071     }
6072     if (c == '.' || isdigit(c)) {
6073 	double d;
6074 	int i, gotdot = 0;
6075 
6076 	i = 0;
6077 	while (c == '.' || isdigit(c)) {
6078 	    if (c == '.') {
6079 		if (gotdot) {
6080 		    yyerror("Reading number, too many dots");
6081 	    	    return 0;
6082 		} else {
6083 		    gotdot = 1;
6084 		}
6085 	    }
6086 	    sbuf[i++] = c;
6087 	    c = getcharstr();
6088 	}
6089 	if (c == 'E' || c == 'e') {
6090 	    sbuf[i++] = c;
6091 	    c = getcharstr();
6092 	    if (c == '+' || c == '-') {
6093 		sbuf[i++] = c;
6094 		c = getcharstr();
6095 	    }
6096 	    while (isdigit(c)) {
6097 		sbuf[i++] = c;
6098 		c = getcharstr();
6099 	    }
6100 	}
6101 	if (gotdot && i == 1) {
6102 	    ungetchstr();
6103 	    return '.';
6104 	}
6105 	sbuf[i] = '\0';
6106 	ungetchstr();
6107 	sscanf(sbuf, "%lf", &d);
6108 	yylval.dval = d;
6109 	return NUMBER;
6110     }
6111 /* graphs, sets, regions resp. */
6112     if (c == 'G' || c == 'S' || c == 'R') {
6113 	int i = 0, ctmp = c, gn, sn, rn;
6114 	c = getcharstr();
6115 	while (isdigit(c) || c == '$' || c == '_') {
6116 	    sbuf[i++] = c;
6117 	    c = getcharstr();
6118 	}
6119 	if (i == 0) {
6120 	    c = ctmp;
6121 	    ungetchstr();
6122 	} else {
6123 	    ungetchstr();
6124 	    if (ctmp == 'G') {
6125 	        sbuf[i] = '\0';
6126 		if (i == 1 && sbuf[0] == '_') {
6127                     gn = get_recent_gno();
6128                 } else if (i == 1 && sbuf[0] == '$') {
6129                     gn = whichgraph;
6130                 } else {
6131                     gn = atoi(sbuf);
6132                 }
6133 		if (is_valid_gno(gn) || graph_allocate(gn) == RETURN_SUCCESS) {
6134 		    yylval.ival = gn;
6135 		    return GRAPHNO;
6136 		}
6137 	    } else if (ctmp == 'S') {
6138 	        sbuf[i] = '\0';
6139 		if (i == 1 && sbuf[0] == '_') {
6140                     sn = get_recent_setno();
6141                 } else if (i == 1 && sbuf[0] == '$') {
6142                     sn = whichset;
6143                 } else {
6144 		    sn = atoi(sbuf);
6145                 }
6146 		yylval.ival = sn;
6147 		return SETNUM;
6148 	    } else if (ctmp == 'R') {
6149 	        sbuf[i] = '\0';
6150 		rn = atoi(sbuf);
6151 		if (rn >= 0 && rn < MAXREGION) {
6152 		    yylval.ival = rn;
6153 		    return REGNUM;
6154 		} else {
6155                     errmsg("Invalid region number");
6156                 }
6157 	    }
6158 	}
6159     }
6160     if (isalpha(c) || c == '$') {
6161 	char *p = sbuf;
6162 
6163 	do {
6164 	    *p++ = c;
6165 	} while ((c = getcharstr()) != EOF && (isalpha(c) || isdigit(c) ||
6166                   c == '_' || c == '$'));
6167 	ungetchstr();
6168 	*p = '\0';
6169 #ifdef DEBUG
6170         if (get_debuglevel() == 2) {
6171 	    printf("->%s<-\n", sbuf);
6172 	}
6173 #endif
6174 	found = -1;
6175 	if ((found = findf(key, sbuf)) >= 0) {
6176 	    if (key[found].type == FITPARM) {
6177 		int index = sbuf[1] - '0';
6178 		yylval.ival = index;
6179 		return FITPARM;
6180 	    }
6181 	    else if (key[found].type == FITPMAX) {
6182 		int index = sbuf[1] - '0';
6183 		yylval.ival = index;
6184 		return FITPMAX;
6185 	    }
6186 	    else if (key[found].type == FITPMIN) {
6187 		int index = sbuf[1] - '0';
6188 		yylval.ival = index;
6189 		return FITPMIN;
6190 	    }
6191 
6192 	    else if (key[found].type == KEY_VAR) {
6193 		yylval.dptr = (double *) key[found].data;
6194 		return VAR_D;
6195 	    }
6196 	    else if (key[found].type == KEY_VEC) {
6197 		yylval.vrbl = (grarr *) key[found].data;
6198 		return VEC_D;
6199 	    }
6200 
6201 	    else if (key[found].type == FUNC_I) {
6202 		yylval.ival = found;
6203 		return FUNC_I;
6204 	    }
6205 	    else if (key[found].type == CONSTANT) {
6206 		yylval.ival = found;
6207 		return CONSTANT;
6208 	    }
6209 	    else if (key[found].type == UCONSTANT) {
6210 		yylval.ival = found;
6211 		return UCONSTANT;
6212 	    }
6213 	    else if (key[found].type == FUNC_D) {
6214 		yylval.ival = found;
6215 		return FUNC_D;
6216 	    }
6217 	    else if (key[found].type == FUNC_ND) {
6218 		yylval.ival = found;
6219 		return FUNC_ND;
6220 	    }
6221 	    else if (key[found].type == FUNC_DD) {
6222 		yylval.ival = found;
6223 		return FUNC_DD;
6224 	    }
6225 	    else if (key[found].type == FUNC_NND) {
6226 		yylval.ival = found;
6227 		return FUNC_NND;
6228 	    }
6229 	    else if (key[found].type == FUNC_PPD) {
6230 		yylval.ival = found;
6231 		return FUNC_PPD;
6232 	    }
6233 	    else if (key[found].type == FUNC_PPPD) {
6234 		yylval.ival = found;
6235 		return FUNC_PPPD;
6236 	    }
6237 	    else if (key[found].type == FUNC_PPPPD) {
6238 		yylval.ival = found;
6239 		return FUNC_PPPPD;
6240 	    }
6241 	    else if (key[found].type == FUNC_PPPPPD) {
6242 		yylval.ival = found;
6243 		return FUNC_PPPPPD;
6244 	    }
6245 	    else {
6246 	        yylval.ival = key[found].type;
6247 	        return key[found].type;
6248 	    }
6249 	} else {
6250 	    yylval.sval = copy_string(NULL, sbuf);
6251 	    return NEW_TOKEN;
6252 	}
6253     }
6254     switch (c) {
6255     case '>':
6256 	return follow('=', GE, GT);
6257     case '<':
6258 	return follow('=', LE, LT);
6259     case '=':
6260 	return follow('=', EQ, '=');
6261     case '!':
6262 	return follow('=', NE, NOT);
6263     case '|':
6264 	return follow('|', OR, '|');
6265     case '&':
6266 	return follow('&', AND, '&');
6267     case '\n':
6268 	return '\n';
6269     default:
6270 	return c;
6271     }
6272 }
6273 
follow(int expect,int ifyes,int ifno)6274 static int follow(int expect, int ifyes, int ifno)
6275 {
6276     int c = getcharstr();
6277 
6278     if (c == expect) {
6279 	return ifyes;
6280     }
6281     ungetchstr();
6282     return ifno;
6283 }
6284 
yyerror(char * s)6285 static void yyerror(char *s)
6286 {
6287     char *buf;
6288 
6289     buf = copy_string(NULL, s);
6290     buf = concat_strings(buf, ": ");
6291     buf = concat_strings(buf, f_string);
6292     errmsg(buf);
6293     xfree(buf);
6294     interr = 1;
6295 }
6296