%{
/*****************************************************************\
 * FILE: hpgl.y   part of hpgl to X windows                      *
 *                                                               *
 * Written by Randy L. Yach aid by Jackie Harrison               *
 * Ported to X11R4 by Andrew Gerber gerber@solbourne.com         *
 *                  Lex & Yacc info from Warner Losh             *
 *                                                               *
 * Description:                                                  *
 *    this is the yacc parser of HPGL syntax.  All plotting      *
 *    line drawing and labeling are done in this procedure       *
\*****************************************************************/

#include <stdio.h>
#include <X11/X.h>
#include <X11/Xlib.h>
#include <math.h>

/* need all these external global variables to interface with the many
   X windows variables. */
extern int hline;
extern char yytext[];
extern double xMin,xMax,yMin,yMax;
extern int last_x, last_y;
extern int x,y;
extern int cur_pen,no_pen;
extern int pen_down;
extern int absolute;
extern XColor pen[];
extern Window main_window;
extern Font text_font;
extern short font_offset;
extern int minWidth,minHeight;
extern line;
extern GC gc;
extern Display *dpy;
XTextItem text;
extern int span_count;
extern int is_color;
extern initialize_plotter();
extern int offscreen, last_offscreen;

/* binary pattern definitions for drawing dashed lines */
/* default |________|  */
/* line 0  |        |  */
/* line 1  |_       |  */
/* line 2  |____    |  */
/* line 3  |______  |  */
/* line 4  |______ _|  */
/* line 5  |_____ __|  */
/* line 6  |____ _ _|  */
unsigned short line_pattern[7] = {
    0x00, 0x80, 0xf0, 0xfc, 0xfd, 0xfb, 0xf5
    };

/* these variables are needed to calculate the default length
   of the patterns used in the dashed lines */
int pat_len;
double pat_perc,tot_dist;

%}

%token LT LB PA PR PU PD SP SC DIGIT SEMICOLON COMMA NUMBER RESET EA EAT_TO_SEMI RA

%start xhpgl_start

%union {
int i;
char sb[BUFSIZ];
float f;
}

%type <i> DIGIT SP
%type <sb> LB
%type <f> NUMBER

%%

xhpgl_start    : /* empty statement */
	       | xhpgl_start xhpgl_commands
	       ;

opt_semicolon  : SEMICOLON
               | ;
  
xhpgl_commands : plot_coordinates cordinate_list opt_semicolon
	       | SP opt_semicolon
		 { /* begin select pen */
		 /* set pen color from the SP command */
		 if (is_color)
		   {
		     cur_pen = pen[$1].pixel; 
		     XSetForeground(dpy, gc, cur_pen); 
		   }
		 } /* end select pen */
	       | SC scale_coordinates SEMICOLON
	       | text_labels
	       | LT line_type_change SEMICOLON
	       | RESET
		 { /* begin reset */
		 initialize_plotter();
		 } /* end reset */
	       ;

line_type_change : /* empty statement */ 
                   { /* begin solid line */
		   /* set up solid line type */
/*		   line_type = XMakePattern(0xff,8,1); */
		   } /* end solid line */
		 | DIGIT COMMA NUMBER
                   { /* begin dashed line */
		   /* set up line pattern */
/*		   pat_perc=($3/100.0);
		   tot_dist=sqrt(pow((float)minWidth,(float)2)
				+pow((float)minHeight,(float)2));
		   pat_len=(int)((pat_perc*tot_dist)/8.0);
		   if (pat_len < 1) pat_len = 1;
		   line_type = XMakePattern(line_pattern[$1],8,pat_len);
*/		   } /* end dashed line */
		 | DIGIT COMMA DIGIT
                   { /* begin dashed line */
		   /* set up line pattern */
/*		   pat_perc=($3/100.0);
		   tot_dist=sqrt(pow((float)minWidth,(float)2)
				+pow((float)minHeight,(float)2));
		   pat_len=(int)((pat_perc*tot_dist)/8.0);
		   if (pat_len < 1) pat_len = 1;
		   line_type = XMakePattern(line_pattern[$1],8,pat_len);
*/		   } /* end dashed line */
		 ;

text_labels    : LB
                 { /* begin plot label */
		 /* plot the text given at the current X,Y locations */
		   text.chars = $1;
		   text.nchars = strlen($1);
		   text.delta = 0;
		   text.font = text_font;
		   
		 XDrawText(dpy, main_window, gc, x,y-font_offset, &text, 1);
		 } /* end plot label */
	       ;	

plot_coordinates : PA
	           { /* begin pen absolute coordinates */
		   absolute = 1;
		   } /* end pen absolute coordinates */
		 | PD
		   { /* begin pen relitave coordinates */
		   pen_down = 1;
		   } /* end pen relitave coordinates */
		 | PU
		   { /* begin pen up coordinates */
		   pen_down = 0;
		   } /* end pen up coordinates */
		 | PR
		   { /* begin pen down coordinates */
		   absolute = 0;
		   } /* end pen down coordinates */
		 ;

scale_coordinates : DIGIT COMMA DIGIT COMMA DIGIT COMMA DIGIT
                    { /* begin user scale */
		    /* set up the user coodinate boundaries */
		    xMin = $1;
		    xMax = $3;
		    yMin = $5;
		    yMax = $7;
                    } /* end user scale */
                  ;

cordinate_list : /* empty statement */
	       | cordinate_list cordinate_def comma_opt
	       ;

comma_opt      : /* empty statement */
	       | COMMA
	       ;

cordinate_def  : DIGIT COMMA DIGIT
                 { /* begin cordinate change */
		 /* get the new x,y points and convert then to absolute
                    X window coodinates based on the user coordinates and 
		    plot scale. */
		 last_x = x;
		 last_y = y;
		 last_offscreen = offscreen;
		 offscreen = 0;

		 if (absolute)
		     { /* begin abs coordinate */
		     x=(double)(($1 - xMin)*(minWidth/(xMax - xMin)));
		     y=(double)(($3 - yMin)*(minHeight/(yMax - yMin)));
		     } /* end abs coordinate */
		 else
		     { /* begin relative coordinate */
		     x=last_x+(double)(($1 - xMin)*(minWidth/(xMax - xMin)));
		     y=last_y+(double)(($3 - yMin)*(minHeight/(yMax - yMin)));
		     } /* end relitave coordinate */

		 /* See if the point is on the screen; if it is not and the last point 
		    was not on the screen, don't paint anything */
		 y = minHeight - y;

		 if ($1 < xMin || $1 > xMax || $3 < yMin && $3 > yMax)
		   offscreen = 1;
		 if (offscreen == 1 && last_offscreen == 1)
		   break;

                 /* if the pen is down, draw a line of the appropriate line
		    type between the last x,y and the current x,y
		    coordinates */
                 if (pen_down)
		     { /* begin draw line */
		     XDrawLine(dpy, main_window, gc, last_x, last_y, x, y);
		     ++span_count;
		     } /* end draw line */
		 } /* end cordinate change */
	       ;

%%
void yyerror(mess)
char *mess;
{ 
/* begin parsing error */
    fprintf(stderr,"Syntax error line %d token %s.\n",hline,yytext); 
/* end parsing error */
/*     exit();  */
} 

int yywrap()
{ /* begin */
	return(1);
} /* end */

