/* This file is automatically generated by Lemon from input grammar
 * ** source file "pikchr.y". */
/*
 * ** Zero-Clause BSD license:
 * **
 * ** Copyright (C) 2020-09-01 by D. Richard Hipp <drh@sqlite.org>
 * **
 * ** Permission to use, copy, modify, and/or distribute this software for
 * ** any purpose with or without fee is hereby granted.
 * **
 * ****************************************************************************
 * **
 * ** This software translates a PIC-inspired diagram language into SVG.
 * **
 * ** PIKCHR (pronounced like "picture") is *mostly* backwards compatible
 * ** with legacy PIC, though some features of legacy PIC are removed 
 * ** (for example, the "sh" command is removed for security) and
 * ** many enhancements are added.
 * **
 * ** PIKCHR is designed for use in an internet facing web environment.
 * ** In particular, PIKCHR is designed to safely generate benign SVG from
 * ** source text that provided by a hostile agent. 
 * **
 * ** This code was originally written by D. Richard Hipp using documentation
 * ** from prior PIC implementations but without reference to prior code.
 * ** All of the code in this project is original.
 * **
 * ** This file implements a C-language subroutine that accepts a string
 * ** of PIKCHR language text and generates a second string of SVG output that
 * ** renders the drawing defined by the input.  Space to hold the returned
 * ** string is obtained from malloc() and should be freed by the caller.
 * ** NULL might be returned if there is a memory allocation error.
 * **
 * ** If there are errors in the PIKCHR input, the output will consist of an
 * ** error message and the original PIKCHR input text (inside of <pre>...</pre>).
 * **
 * ** The subroutine implemented by this file is intended to be stand-alone.
 * ** It uses no external routines other than routines commonly found in
 * ** the standard C library.
 * **
 * ****************************************************************************
 * ** COMPILING:
 * **
 * ** The original source text is a mixture of C99 and "Lemon"
 * ** (See https://sqlite.org/src/file/doc/lemon.html).  Lemon is an LALR(1)
 * ** parser generator program, similar to Yacc.  The grammar of the
 * ** input language is specified in Lemon.  C-code is attached.  Lemon
 * ** runs to generate a single output file ("pikchr.c") which is then
 * ** compiled to generate the Pikchr library.  This header comment is
 * ** preserved in the Lemon output, so you might be reading this in either
 * ** the generated "pikchr.c" file that is output by Lemon, or in the
 * ** "pikchr.y" source file that is input into Lemon.  If you make changes,
 * ** you should change the input source file "pikchr.y", not the
 * ** Lemon-generated output file.
 * **
 * ** Basic compilation steps:
 * **
 * **      lemon pikchr.y
 * **      cc pikchr.c -o pikchr.o
 * **
 * ** Add -DPIKCHR_SHELL to add a main() routine that reads input files
 * ** and sends them through Pikchr, for testing.  Add -DPIKCHR_FUZZ for
 * ** -fsanitizer=fuzzer testing.
 * ** 
 * ****************************************************************************
 * ** IMPLEMENTATION NOTES (for people who want to understand the internal
 * ** operation of this software, perhaps to extend the code or to fix bugs):
 * **
 * ** Each call to pikchr() uses a single instance of the Pik structure to
 * ** track its internal state.  The Pik structure lives for the duration
 * ** of the pikchr() call.
 * **
 * ** The input is a sequence of objects or "statements".  Each statement is
* ** parsed into a PObj object.  These are stored on an extensible array
	* ** called PList.  All parameters to each PObj are computed as the
	     * ** object is parsed.  (Hence, the parameters to a PObj may only refer
			     * ** to prior statements.) Once the PObj is completely assembled, it is
			   * ** added to the end of a PList and never changes thereafter - except,
			   * ** PObj objects that are part of a "[...]" block might have their
			   * ** absolute position shifted when the outer [...] block is positioned.
			   * ** But apart from this repositioning, PObj objects are unchanged once
			   * ** they are added to the list. The order of statements on a PList does
			   * ** not change.
			   * **
			   * ** After all input has been parsed, the top-level PList is walked to
			   * ** generate output.  Sub-lists resulting from [...] blocks are scanned
			   * ** as they are encountered.  All input must be collected and parsed ahead
			   * ** of output generation because the size and position of statements must be
			   * ** known in order to compute a bounding box on the output.
			   * **
			   * ** Each PObj is on a "layer".  (The common case is that all PObj's are
					   * ** on a single layer, but multiple layers are possible.)  A separate pass
					 * ** is made through the list for each layer.
					 * **
					 * ** After all output is generated, the Pik object and all the PList
					 * ** and PObj objects are deallocated and the generated output string is
					 * ** returned.  Upon any error, the Pik.nErr flag is set, processing quickly
					 * ** stops, and the stack unwinds.  No attempt is made to continue reading
					 * ** input after an error.
					 * **
					 * ** Most statements begin with a class name like "box" or "arrow" or "move".
					 * ** There is a class named "text" which is used for statements that begin
					 * ** with a string literal.  You can also specify the "text" class.
					 * ** A Sublist ("[...]") is a single object that contains a pointer to
					 * ** its substatements, all gathered onto a separate PList object.
					 * **
					 * ** Variables go into PVar objects that form a linked list.
					 * **
					 * ** Each PObj has zero or one names.  Input constructs that attempt
					 * ** to assign a new name from an older name, for example:
					 * **
					 * **      Abc:  Abc + (0.5cm, 0)
					 * **
					 * ** Statements like these generate a new "noop" object at the specified
					 * ** place and with the given name. As place-names are searched by scanning
					 * ** the list in reverse order, this has the effect of overriding the "Abc"
					 * ** name when referenced by subsequent objects.
					 * */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <math.h>
#include <assert.h>
#define count(X) (sizeof(X)/sizeof(X[0]))
#ifndef M_PI
# define M_PI 3.1415926535897932385
#endif

					 /* Tag intentionally unused parameters with this macro to prevent
					  * ** compiler warnings with -Wextra */
#define UNUSED_PARAMETER(X)  (void)(X)

					 typedef struct Pik Pik;          /* Complete parsing context */
					 typedef struct PToken PToken;    /* A single token */
					 typedef struct PObj PObj;        /* A single diagram object */
					 typedef struct PList PList;      /* A list of diagram objects */
					 typedef struct PClass PClass;    /* Description of statements types */
					 typedef double PNum;             /* Numeric value */
					 typedef struct PRel PRel;        /* Absolute or percentage value */
					 typedef struct PPoint PPoint;    /* A position in 2-D space */
					 typedef struct PVar PVar;        /* script-defined variable */
					 typedef struct PBox PBox;        /* A bounding box */
					 typedef struct PMacro PMacro;    /* A "define" macro */

					 /* Compass points */
#define CP_N      1
#define CP_NE     2
#define CP_E      3
#define CP_SE     4
#define CP_S      5
#define CP_SW     6
#define CP_W      7
#define CP_NW     8
#define CP_C      9   /* .center or .c */
#define CP_END   10   /* .end */
#define CP_START 11   /* .start */

					 /* Heading angles corresponding to compass points */
					 static const PNum pik_hdg_angle[] = {
						 /* none  */   0.0,
						   /* N  */    0.0,
						     /* NE */   45.0,
						       /* E  */   90.0,
						         /* SE */  135.0,
							   /* S  */  180.0,
							     /* SW */  225.0,
							       /* W  */  270.0,
							         /* NW */  315.0,
								   /* C  */    0.0,
					 };

/* Built-in functions */
#define FN_ABS    0
#define FN_COS    1
#define FN_INT    2
#define FN_MAX    3
#define FN_MIN    4
#define FN_SIN    5
#define FN_SQRT   6

/* Text position and style flags.  Stored in PToken.eCode so limited
 * ** to 15 bits. */
#define TP_LJUST   0x0001  /* left justify......          */
#define TP_RJUST   0x0002  /*            ...Right justify */
#define TP_JMASK   0x0003  /* Mask for justification bits */
#define TP_ABOVE2  0x0004  /* Position text way above PObj.ptAt */
#define TP_ABOVE   0x0008  /* Position text above PObj.ptAt */
#define TP_CENTER  0x0010  /* On the line */
#define TP_BELOW   0x0020  /* Position text below PObj.ptAt */
#define TP_BELOW2  0x0040  /* Position text way below PObj.ptAt */
#define TP_VMASK   0x007c  /* Mask for text positioning flags */
#define TP_BIG     0x0100  /* Larger font */
#define TP_SMALL   0x0200  /* Smaller font */
#define TP_XTRA    0x0400  /* Amplify TP_BIG or TP_SMALL */
#define TP_SZMASK  0x0700  /* Font size mask */
#define TP_ITALIC  0x1000  /* Italic font */
#define TP_BOLD    0x2000  /* Bold font */
#define TP_FMASK   0x3000  /* Mask for font style */
#define TP_ALIGN   0x4000  /* Rotate to align with the line */

/* An object to hold a position in 2-D space */
struct PPoint {
	  PNum x, y;             /* X and Y coordinates */
};
static const PPoint cZeroPoint = {0.0,0.0};

/* A bounding box */
struct PBox {
	  PPoint sw, ne;         /* Lower-left and top-right corners */
};

/* An Absolute or a relative distance.  The absolute distance
 * ** is stored in rAbs and the relative distance is stored in rRel.
 * ** Usually, one or the other will be 0.0.  When using a PRel to
 * ** update an existing value, the computation is usually something
 * ** like this:
 * **
 * **          value = PRel.rAbs + value*PRel.rRel
 * **
 * */
struct PRel {
	  PNum rAbs;            /* Absolute value */
	    PNum rRel;            /* Value relative to current value */
};

/* A variable created by the ID = EXPR construct of the PIKCHR script 
 * **
 * ** PIKCHR (and PIC) scripts do not use many varaibles, so it is reasonable
 * ** to store them all on a linked list.
 * */
struct PVar {
	  const char *zName;       /* Name of the variable */
	    PNum val;                /* Value of the variable */
	      PVar *pNext;             /* Next variable in a list of them all */
};

/* A single token in the parser input stream
 * */
struct PToken {
	  const char *z;             /* Pointer to the token text */
	    unsigned int n;            /* Length of the token in bytes */
	      short int eCode;           /* Auxiliary code */
	        unsigned char eType;       /* The numeric parser code */
		  unsigned char eEdge;       /* Corner value for corner keywords */
};

/* Return negative, zero, or positive if pToken is less than, equal to
 * ** or greater than the zero-terminated string z[]
 * */
static int pik_token_eq(PToken *pToken, const char *z){
	  int c = strncmp(pToken->z,z,pToken->n);
	    if( c==0 && z[pToken->n]!=0 ) c = -1;
	      return c;
}

/* Extra token types not generated by LEMON but needed by the
 * ** tokenizer
 * */
#define T_PARAMETER  253     /* $1, $2, ..., $9 */
#define T_WHITESPACE 254     /* Whitespace of comments */
#define T_ERROR      255     /* Any text that is not a valid token */

/* Directions of movement */
#define DIR_RIGHT     0
#define DIR_DOWN      1
#define DIR_LEFT      2
#define DIR_UP        3
#define ValidDir(X)     ((X)>=0 && (X)<=3)
#define IsUpDown(X)     (((X)&1)==1)
#define IsLeftRight(X)  (((X)&1)==0)

/* Bitmask for the various attributes for PObj.  These bits are
 * ** collected in PObj.mProp and PObj.mCalc to check for constraint
 * ** errors. */
#define A_WIDTH         0x0001
#define A_HEIGHT        0x0002
#define A_RADIUS        0x0004
#define A_THICKNESS     0x0008
#define A_DASHED        0x0010 /* Includes "dotted" */
#define A_FILL          0x0020
#define A_COLOR         0x0040
#define A_ARROW         0x0080
#define A_FROM          0x0100
#define A_CW            0x0200
#define A_AT            0x0400
#define A_TO            0x0800 /* one or more movement attributes */
#define A_FIT           0x1000


/* A single graphics object */
struct PObj {
	  const PClass *type;      /* Object type or class */
	    PToken errTok;           /* Reference token for error messages */
	      PPoint ptAt;             /* Reference point for the object */
	        PPoint ptEnter, ptExit;  /* Entry and exit points */
		  PList *pSublist;         /* Substructure for [...] objects */
		    char *zName;             /* Name assigned to this statement */
		      PNum w;                  /* "width" property */
		        PNum h;                  /* "height" property */
			  PNum rad;                /* "radius" property */
			    PNum sw;                 /* "thickness" property. (Mnemonic: "stroke width")*/
			      PNum dotted;             /* "dotted" property.   <=0.0 for off */
			        PNum dashed;             /* "dashed" property.   <=0.0 for off */
				  PNum fill;               /* "fill" property.  Negative for off */
				    PNum color;              /* "color" property */
				      PPoint with;             /* Position constraint from WITH clause */
				        char eWith;              /* Type of heading point on WITH clause */
					  char cw;                 /* True for clockwise arc */
					    char larrow;             /* Arrow at beginning (<- or <->) */
					      char rarrow;             /* Arrow at end  (-> or <->) */
					        char bClose;             /* True if "close" is seen */
						  char bChop;              /* True if "chop" is seen */
						    unsigned char nTxt;      /* Number of text values */
						      unsigned mProp;          /* Masks of properties set so far */
						        unsigned mCalc;          /* Values computed from other constraints */
							  PToken aTxt[5];          /* Text with .eCode holding TP flags */
							    int iLayer;              /* Rendering order */
							      int inDir, outDir;       /* Entry and exit directions */
							        int nPath;               /* Number of path points */
								  PPoint *aPath;           /* Array of path points */
								    PBox bbox;               /* Bounding box */
};

/* A list of graphics objects */
struct PList {
	  int n;          /* Number of statements in the list */
	    int nAlloc;     /* Allocated slots in a[] */
	      PObj **a;       /* Pointers to individual objects */
};

/* A macro definition */
struct PMacro {
	  PMacro *pNext;       /* Next in the list */
	    PToken macroName;    /* Name of the macro */
	      PToken macroBody;    /* Body of the macro */
	        int inUse;           /* Do not allow recursion */
};

/* Each call to the pikchr() subroutine uses an instance of the following
 * ** object to pass around context to all of its subroutines.
 * */
struct Pik {
	  unsigned nErr;           /* Number of errors seen */
	    PToken sIn;              /* Input Pikchr-language text */
	      char *zOut;              /* Result accumulates here */
	        unsigned int nOut;       /* Bytes written to zOut[] so far */
		  unsigned int nOutAlloc;  /* Space allocated to zOut[] */
		    unsigned char eDir;      /* Current direction */
		      unsigned int mFlags;     /* Flags passed to pikchr() */
		        PObj *cur;               /* Object under construction */
			  PList *list;             /* Object list under construction */
			    PMacro *pMacros;         /* List of all defined macros */
			      PVar *pVar;              /* Application-defined variables */
			        PBox bbox;               /* Bounding box around all statements */
				                           /* Cache of layout values.  <=0.0 for unknown... */
				  PNum rScale;                 /* Multiply to convert inches to pixels */
				    PNum fontScale;              /* Scale fonts by this percent */
				      PNum charWidth;              /* Character width */
				        PNum charHeight;             /* Character height */
					  PNum wArrow;                 /* Width of arrowhead at the fat end */
					    PNum hArrow;                 /* Ht of arrowhead - dist from tip to fat end */
					      char bLayoutVars;            /* True if cache is valid */
					        char thenFlag;           /* True if "then" seen */
						  char samePath;           /* aTPath copied by "same" */
						    const char *zClass;      /* Class name for the <svg> */
						      int wSVG, hSVG;          /* Width and height of the <svg> */
						        /* Paths for lines are constructed here first, then transferred into
							 *   ** the PObj object at the end: */
						        int nTPath;              /* Number of entries on aTPath[] */
							  int mTPath;              /* For last entry, 1: x set,  2: y set */
							    PPoint aTPath[1000];     /* Path under construction */
							      /* Error contexts */
							      unsigned int nCtx;       /* Number of error contexts */
							        PToken aCtx[10];         /* Nested error contexts */
};


/*
 * ** The behavior of an object class is defined by an instance of
 * ** this structure. This is the "virtual method" table.
 * */
struct PClass {
	  const char *zName;                     /* Name of class */
	    char isLine;                           /* True if a line class */
	      char eJust;                            /* Use box-style text justification */
	        void (*xInit)(Pik*,PObj*);              /* Initializer */
		  void (*xNumProp)(Pik*,PObj*,PToken*);   /* Value change notification */
		    void (*xCheck)(Pik*,PObj*);             /* Checks to do after parsing */
		      PPoint (*xChop)(Pik*,PObj*,PPoint*);    /* Chopper */
		        PPoint (*xOffset)(Pik*,PObj*,int);      /* Offset from .c to edge point */
			  void (*xFit)(Pik*,PObj*,PNum w,PNum h); /* Size to fit text */
			    void (*xRender)(Pik*,PObj*);            /* Render */
};


/* Forward declarations */
static void pik_append(Pik*, const char*,int);
static void pik_append_text(Pik*,const char*,int,int);
static void pik_append_num(Pik*,const char*,PNum);
static void pik_append_point(Pik*,const char*,PPoint*);
static void pik_append_x(Pik*,const char*,PNum,const char*);
static void pik_append_y(Pik*,const char*,PNum,const char*);
static void pik_append_xy(Pik*,const char*,PNum,PNum);
static void pik_append_dis(Pik*,const char*,PNum,const char*);
static void pik_append_arc(Pik*,PNum,PNum,PNum,PNum);
static void pik_append_clr(Pik*,const char*,PNum,const char*);
static void pik_append_style(Pik*,PObj*,int);
static void pik_append_txt(Pik*,PObj*, PBox*);
static void pik_draw_arrowhead(Pik*,PPoint*pFrom,PPoint*pTo,PObj*);
static void pik_chop(PPoint*pFrom,PPoint*pTo,PNum);
static void pik_error(Pik*,PToken*,const char*);
static void pik_elist_free(Pik*,PList*);
static void pik_elem_free(Pik*,PObj*);
static void pik_render(Pik*,PList*);
static PList *pik_elist_append(Pik*,PList*,PObj*);
static PObj *pik_elem_new(Pik*,PToken*,PToken*,PList*);
static void pik_set_direction(Pik*,int);
static void pik_elem_setname(Pik*,PObj*,PToken*);
static void pik_set_var(Pik*,PToken*,PNum,PToken*);
static PNum pik_value(Pik*,const char*,int,int*);
static PNum pik_lookup_color(Pik*,PToken*);
static PNum pik_get_var(Pik*,PToken*);
static PNum pik_atof(PToken*);
static void pik_after_adding_attributes(Pik*,PObj*);
static void pik_elem_move(PObj*,PNum dx, PNum dy);
static void pik_elist_move(PList*,PNum dx, PNum dy);
static void pik_set_numprop(Pik*,PToken*,PRel*);
static void pik_set_clrprop(Pik*,PToken*,PNum);
static void pik_set_dashed(Pik*,PToken*,PNum*);
static void pik_then(Pik*,PToken*,PObj*);
static void pik_add_direction(Pik*,PToken*,PRel*);
static void pik_move_hdg(Pik*,PRel*,PToken*,PNum,PToken*,PToken*);
static void pik_evenwith(Pik*,PToken*,PPoint*);
static void pik_set_from(Pik*,PObj*,PToken*,PPoint*);
static void pik_add_to(Pik*,PObj*,PToken*,PPoint*);
static void pik_close_path(Pik*,PToken*);
static void pik_set_at(Pik*,PToken*,PPoint*,PToken*);
static short int pik_nth_value(Pik*,PToken*);
static PObj *pik_find_nth(Pik*,PObj*,PToken*);
static PObj *pik_find_byname(Pik*,PObj*,PToken*);
static PPoint pik_place_of_elem(Pik*,PObj*,PToken*);
static int pik_bbox_isempty(PBox*);
static void pik_bbox_init(PBox*);
static void pik_bbox_addbox(PBox*,PBox*);
static void pik_bbox_add_xy(PBox*,PNum,PNum);
static void pik_bbox_addellipse(PBox*,PNum x,PNum y,PNum rx,PNum ry);
static void pik_add_txt(Pik*,PToken*,int);
static int pik_text_length(const PToken *pToken);
static void pik_size_to_fit(Pik*,PToken*,int);
static int pik_text_position(int,PToken*);
static PNum pik_property_of(PObj*,PToken*);
static PNum pik_func(Pik*,PToken*,PNum,PNum);
static PPoint pik_position_between(PNum x, PPoint p1, PPoint p2);
static PPoint pik_position_at_angle(PNum dist, PNum r, PPoint pt);
static PPoint pik_position_at_hdg(PNum dist, PToken *pD, PPoint pt);
static void pik_same(Pik *p, PObj*, PToken*);
static PPoint pik_nth_vertex(Pik *p, PToken *pNth, PToken *pErr, PObj *pObj);
static PToken pik_next_semantic_token(PToken *pThis);
static void pik_compute_layout_settings(Pik*);
static void pik_behind(Pik*,PObj*);
static PObj *pik_assert(Pik*,PNum,PToken*,PNum);
static PObj *pik_position_assert(Pik*,PPoint*,PToken*,PPoint*);
static PNum pik_dist(PPoint*,PPoint*);
static void pik_add_macro(Pik*,PToken *pId,PToken *pCode);


#line 494 "pikchr.c"
/**************** End of %include directives **********************************/
/* These constants specify the various numeric values for terminal symbols.
 * ***************** Begin token definitions *************************************/
#ifndef T_ID
#define T_ID                              1
#define T_EDGEPT                          2
#define T_OF                              3
#define T_PLUS                            4
#define T_MINUS                           5
#define T_STAR                            6
#define T_SLASH                           7
#define T_PERCENT                         8
#define T_UMINUS                          9
#define T_EOL                            10
#define T_ASSIGN                         11
#define T_PLACENAME                      12
#define T_COLON                          13
#define T_ASSERT                         14
#define T_LP                             15
#define T_EQ                             16
#define T_RP                             17
#define T_DEFINE                         18
#define T_CODEBLOCK                      19
#define T_FILL                           20
#define T_COLOR                          21
#define T_THICKNESS                      22
#define T_PRINT                          23
#define T_STRING                         24
#define T_COMMA                          25
#define T_CLASSNAME                      26
#define T_LB                             27
#define T_RB                             28
#define T_UP                             29
#define T_DOWN                           30
#define T_LEFT                           31
#define T_RIGHT                          32
#define T_CLOSE                          33
#define T_CHOP                           34
#define T_FROM                           35
#define T_TO                             36
#define T_THEN                           37
#define T_HEADING                        38
#define T_GO                             39
#define T_AT                             40
#define T_WITH                           41
#define T_SAME                           42
#define T_AS                             43
#define T_FIT                            44
#define T_BEHIND                         45
#define T_UNTIL                          46
#define T_EVEN                           47
#define T_DOT_E                          48
#define T_HEIGHT                         49
#define T_WIDTH                          50
#define T_RADIUS                         51
#define T_DIAMETER                       52
#define T_DOTTED                         53
#define T_DASHED                         54
#define T_CW                             55
#define T_CCW                            56
#define T_LARROW                         57
#define T_RARROW                         58
#define T_LRARROW                        59
#define T_INVIS                          60
#define T_THICK                          61
#define T_THIN                           62
#define T_CENTER                         63
#define T_LJUST                          64
#define T_RJUST                          65
#define T_ABOVE                          66
#define T_BELOW                          67
#define T_ITALIC                         68
#define T_BOLD                           69
#define T_ALIGNED                        70
#define T_BIG                            71
#define T_SMALL                          72
#define T_AND                            73
#define T_LT                             74
#define T_GT                             75
#define T_ON                             76
#define T_WAY                            77
#define T_BETWEEN                        78
#define T_THE                            79
#define T_NTH                            80
#define T_VERTEX                         81
#define T_TOP                            82
#define T_BOTTOM                         83
#define T_START                          84
#define T_END                            85
#define T_IN                             86
#define T_DOT_U                          87
#define T_LAST                           88
#define T_NUMBER                         89
#define T_FUNC1                          90
#define T_FUNC2                          91
#define T_DIST                           92
#define T_DOT_XY                         93
#define T_X                              94
#define T_Y                              95
#define T_DOT_L                          96
#endif
/**************** End token definitions ***************************************/

/* The next sections is a series of control #defines.
 * ** various aspects of the generated parser.
 * **    YYCODETYPE         is the data type used to store the integer codes
 * **                       that represent terminal and non-terminal symbols.
 * **                       "unsigned char" is used if there are fewer than
 * **                       256 symbols.  Larger types otherwise.
 * **    YYNOCODE           is a number of type YYCODETYPE that is not used for
 * **                       any terminal or nonterminal symbol.
 * **    YYFALLBACK         If defined, this indicates that one or more tokens
 * **                       (also known as: "terminal symbols") have fall-back
 * **                       values which should be used if the original symbol
 * **                       would not parse.  This permits keywords to sometimes
 * **                       be used as identifiers, for example.
 * **    YYACTIONTYPE       is the data type used for "action codes" - numbers
 * **                       that indicate what to do in response to the next
 * **                       token.
 * **    pik_parserTOKENTYPE     is the data type used for minor type for terminal
 * **                       symbols.  Background: A "minor type" is a semantic
 * **                       value associated with a terminal or non-terminal
 * **                       symbols.  For example, for an "ID" terminal symbol,
 * **                       the minor type might be the name of the identifier.
 * **                       Each non-terminal can have a different minor type.
 * **                       Terminal symbols all have the same minor type, though.
 * **                       This macros defines the minor type for terminal 
 * **                       symbols.
 * **    YYMINORTYPE        is the data type used for all minor types.
 * **                       This is typically a union of many types, one of
 * **                       which is pik_parserTOKENTYPE.  The entry in the union
 * **                       for terminal symbols is called "yy0".
 * **    YYSTACKDEPTH       is the maximum depth of the parser's stack.  If
 * **                       zero the stack is dynamically sized using realloc()
 * **    pik_parserARG_SDECL     A static variable declaration for the %extra_argument
 * **    pik_parserARG_PDECL     A parameter declaration for the %extra_argument
 * **    pik_parserARG_PARAM     Code to pass %extra_argument as a subroutine parameter
 * **    pik_parserARG_STORE     Code to store %extra_argument into yypParser
 * **    pik_parserARG_FETCH     Code to extract %extra_argument from yypParser
 * **    pik_parserCTX_*         As pik_parserARG_ except for %extra_context
 * **    YYERRORSYMBOL      is the code number of the error symbol.  If not
 * **                       defined, then do no error processing.
 * **    YYNSTATE           the combined number of states.
 * **    YYNRULE            the number of rules in the grammar
 * **    YYNTOKEN           Number of terminal symbols
 * **    YY_MAX_SHIFT       Maximum value for shift actions
 * **    YY_MIN_SHIFTREDUCE Minimum value for shift-reduce actions
 * **    YY_MAX_SHIFTREDUCE Maximum value for shift-reduce actions
 * **    YY_ERROR_ACTION    The yy_action[] code for syntax error
 * **    YY_ACCEPT_ACTION   The yy_action[] code for accept
 * **    YY_NO_ACTION       The yy_action[] code for no-op
 * **    YY_MIN_REDUCE      Minimum value for reduce actions
 * **    YY_MAX_REDUCE      Maximum value for reduce actions
 * */
#ifndef INTERFACE
# define INTERFACE 1
#endif
/************* Begin control #defines *****************************************/
#define YYCODETYPE unsigned char
#define YYNOCODE 133
#define YYACTIONTYPE unsigned short int
#define pik_parserTOKENTYPE PToken
typedef union {
	  int yyinit;
	    pik_parserTOKENTYPE yy0;
	      int yy46;
	        PPoint yy47;
		  PNum yy121;
		    PRel yy134;
		      PObj* yy138;
		        PList* yy191;
} YYMINORTYPE;
#ifndef YYSTACKDEPTH
#define YYSTACKDEPTH 100
#endif
#define pik_parserARG_SDECL
#define pik_parserARG_PDECL
#define pik_parserARG_PARAM
#define pik_parserARG_FETCH
#define pik_parserARG_STORE
#define pik_parserCTX_SDECL Pik *p;
#define pik_parserCTX_PDECL ,Pik *p
#define pik_parserCTX_PARAM ,p
#define pik_parserCTX_FETCH Pik *p=yypParser->p;
#define pik_parserCTX_STORE yypParser->p=p;
#define YYFALLBACK 1
#define YYNSTATE             164
#define YYNRULE              154
#define YYNRULE_WITH_ACTION  114
#define YYNTOKEN             97
#define YY_MAX_SHIFT         163
#define YY_MIN_SHIFTREDUCE   285
#define YY_MAX_SHIFTREDUCE   438
#define YY_ERROR_ACTION      439
#define YY_ACCEPT_ACTION     440
#define YY_NO_ACTION         441
#define YY_MIN_REDUCE        442
#define YY_MAX_REDUCE        595
/************* End control #defines *******************************************/
#define YY_NLOOKAHEAD ((int)(sizeof(yy_lookahead)/sizeof(yy_lookahead[0])))

/* Define the yytestcase() macro to be a no-op if is not already defined
 * ** otherwise.
 * **
 * ** Applications can choose to define yytestcase() in the %include section
 * ** to a macro that can assist in verifying code coverage.  For production
 * ** code the yytestcase() macro should be turned off.  But it is useful
 * ** for testing.
 * */
#ifndef yytestcase
# define yytestcase(X)
#endif


/* Next are the tables used to determine what action to take based on the
 * ** current state and lookahead token.  These tables are used to implement
 * ** functions that take a state number and lookahead value and return an
 * ** action integer.  
 * **
 * ** Suppose the action integer is N.  Then the action is determined as
 * ** follows
 * **
 * **   0 <= N <= YY_MAX_SHIFT             Shift N.  That is, push the lookahead
 * **                                      token onto the stack and goto state N.
 * **
 * **   N between YY_MIN_SHIFTREDUCE       Shift to an arbitrary state then
 * **     and YY_MAX_SHIFTREDUCE           reduce by rule N-YY_MIN_SHIFTREDUCE.
 * **
 * **   N == YY_ERROR_ACTION               A syntax error has occurred.
 * **
 * **   N == YY_ACCEPT_ACTION              The parser accepts its input.
 * **
 * **   N == YY_NO_ACTION                  No such action.  Denotes unused
 * **                                      slots in the yy_action[] table.
 * **
 * **   N between YY_MIN_REDUCE            Reduce by rule N-YY_MIN_REDUCE
 * **     and YY_MAX_REDUCE
 * **
 * ** The action table is constructed as a single large table named yy_action[].
 * ** Given state S and lookahead X, the action is computed as either:
 * **
 * **    (A)   N = yy_action[ yy_shift_ofst[S] + X ]
 * **    (B)   N = yy_default[S]
 * **
 * ** The (A) formula is preferred.  The B formula is used instead if
 * ** yy_lookahead[yy_shift_ofst[S]+X] is not equal to X.
 * **
 * ** The formulas above are for computing the action when the lookahead is
 * ** a terminal symbol.  If the lookahead is a non-terminal (as occurs after
 * ** a reduce action) then the yy_reduce_ofst[] array is used in place of
 * ** the yy_shift_ofst[] array.
 * **
 * ** The following are the tables generated in this section:
 * **
 * **  yy_action[]        A single table containing all actions.
 * **  yy_lookahead[]     A table containing the lookahead for each entry in
 * **                     yy_action.  Used to detect hash collisions.
 * **  yy_shift_ofst[]    For each state, the offset into yy_action for
 * **                     shifting terminals.
 * **  yy_reduce_ofst[]   For each state, the offset into yy_action for
 * **                     shifting non-terminals after a reduce.
 * **  yy_default[]       Default action for each state.
 * **
 * *********** Begin parsing tables **********************************************/
#define YY_ACTTAB_COUNT (1223)
static const YYACTIONTYPE yy_action[] = {
	 /*     0 */   569,  491,  161,  119,   25,  448,   29,   74,  129,  148,
	  /*    10 */   569,  488,  161,  119,  449,  113,  120,  161,  119,  525,
	   /*    20 */   423,  424,  337,  553,   81,   36,  554,  555,  569,   64,
	    /*    30 */    63,   62,   61,  320,  321,    9,    8,   33,  149,   32,
	     /*    40 */     7,   71,  127,  308,  333,   66,  523,  161,  119,  337,
	      /*    50 */   337,  337,  337,  421,  422,  338,  339,  340,  341,  342,
	       /*    60 */   343,  344,  345,  470,   64,   63,   62,   61,  311,   28,
	        /*    70 */    73,  304,  148,  470,  528,  161,  119,  112,  113,  120,
		 /*    80 */   161,  119,  128,  423,  424,  337,  354,   81,  526,  161,
		  /*    90 */   119,  470,  374,  158,   13,   30,  320,  321,    9,    8,
		   /*   100 */    33,  149,   32,    7,   71,  127,  372,  333,   66,  573,
		    /*   110 */   328,   31,  337,  337,  337,  337,  421,  422,  338,  339,
		     /*   120 */   340,  341,  342,  343,  344,  345,  390,  431,  326,   59,
		      /*   130 */    60,  407,  408,  409,  410,  374,  158,  372,   35,  390,
		       /*   140 */     2,   38,   59,   60,   48,   37,   46,  162,  442,   80,
		        /*   150 */   372,  306,   79,   42,  118,   83,  437,  436,   36,  390,
			 /*   160 */   431,   84,   59,   60,   47,  297,  571,   77,  571,  122,
			  /*   170 */   372,  296,  390,    2,  108,   59,   60,   76,  156,  156,
			   /*   180 */   156,    3,  117,  372,  132,  130,   42,   69,  430,  437,
			    /*   190 */   436,    4,  390,  431,   67,   59,   60,  118,   64,   63,
			     /*   200 */    62,   61,    5,  372,    6,  106,    2,  432,  433,  434,
			      /*   210 */   435,  387,    1,  117,  389,  155,  154,  153,  106,   49,
			       /*   220 */   420,  430,  437,  436,  107,   65,  117,  389,  155,  154,
			        /*   230 */   153,   54,   51,  120,  161,  119,  419,  459,  106,  131,
				 /*   240 */   432,  433,  434,  435,   78,   78,  117,  389,  155,  154,
				  /*   250 */   153,  106,  393,  390,  430,  152,   59,   60,   11,  117,
				   /*   260 */   389,  155,  154,  153,  102,  376,  157,   42,  394,  395,
				    /*   270 */    69,  106,  353,  432,  433,  434,  435,  375,  159,  117,
				     /*   280 */   389,  155,  154,  153,  142,  140,   64,   63,   62,   61,
				      /*   290 */    12,   64,   63,   62,   61,   62,   61,  428,   45,  138,
				       /*   300 */   139,  142,  140,   64,   63,   62,   61,   55,   64,   63,
				        /*   310 */    62,   61,  426,  147,  146,  390,  387,   44,   59,   60,
					 /*   320 */    43,  295,   15,   14,   55,   16,  102,   18,   19,   42,
					  /*   330 */   147,  146,  106,   20,  299,  300,  301,   43,  303,   68,
					   /*   340 */   117,  389,  155,  154,  153,  444,  450,   29,   22,   21,
					    /*   350 */   114,  446,  356,   23,   26,   57,   24,   58,  145,  141,
					     /*   360 */   427,  388,  163,  380,  373,   22,   21,   27,  160,  378,
					      /*   370 */    70,  379,   39,   24,  441,  145,  141,  427,  142,  140,
					       /*   380 */    64,   63,   62,   61,  347,  347,  347,  347,  347,  347,
					        /*   390 */   347,  347,  347,  347,  106,  441,  441,   64,   63,   62,
						 /*   400 */    61,   55,  117,  389,  155,  154,  153,  147,  146,  399,
						  /*   410 */   387,  441,  441,  441,   43,  441,  441,  441,   52,  441,
						   /*   420 */   133,  441,  126,  441,  441,  441,  123,  441,  400,  401,
						    /*   430 */   402,  404,   80,  441,  306,   79,  441,  407,  408,  409,
						     /*   440 */   410,  441,   22,   21,  390,  441,  441,   59,   60,  441,
						      /*   450 */    24,  441,  145,  141,  427,  372,  441,  441,   42,  441,
						       /*   460 */   441,  441,  441,  156,  156,  156,  390,  469,  441,   59,
						        /*   470 */    60,  390,  143,  441,   59,   60,  441,  372,  441,  529,
							 /*   480 */    42,  441,  372,  441,  441,   42,  441,  390,  144,  441,
							  /*   490 */    59,   60,  441,  390,  441,  441,   59,   60,  372,  441,
							   /*   500 */   441,   42,  441,  469,  372,   88,  390,   40,  441,   59,
							    /*   510 */    60,  441,  441,  441,  120,  161,  119,  372,  529,  441,
							     /*   520 */    41,   82,  441,  106,  529,  441,  441,  529,  462,  441,
							      /*   530 */    34,  117,  389,  155,  154,  153,  152,   85,   64,   63,
							       /*   540 */    62,   61,  441,  441,  441,  106,  120,  161,  119,  441,
							        /*   550 */   106,  441,  441,  117,  389,  155,  154,  153,  117,  389,
								 /*   560 */   155,  154,  153,  441,  441,  441,  106,  441,  152,   17,
								  /*   570 */   441,  441,  106,  441,  117,  389,  155,  154,  153,  431,
								   /*   580 */   117,  389,  155,  154,  153,  106,  441,  423,  424,  337,
								    /*   590 */   441,  441,   86,  117,  389,  155,  154,  153,  441,  441,
								     /*   600 */   441,  120,  161,  119,  121,  443,  450,   29,  437,  436,
								      /*   610 */   441,  446,   64,   63,   62,   61,  337,  337,  337,  337,
								       /*   620 */   421,  422,  163,  152,  441,   75,  440,   27,  109,  443,
								        /*   630 */   450,   29,  441,   50,   74,  446,  148,  441,  441,  441,
									 /*   640 */   430,  124,  113,  120,  161,  119,  163,   72,  441,  148,
									  /*   650 */   441,   27,  431,  441,  125,  113,  120,  161,  119,  432,
									   /*   660 */   433,  434,  435,  441,   74,  149,  148,   64,   63,   62,
									    /*   670 */    61,  493,  113,  120,  161,  119,  441,   74,  149,  148,
									     /*   680 */   352,  437,  436,  441,  492,  113,  120,  161,  119,   74,
									      /*   690 */   441,  148,  441,  441,   98,  149,  486,  113,  120,  161,
									       /*   700 */   119,  441,  441,  120,  161,  119,  441,   74,  149,  148,
									        /*   710 */   441,  441,  441,  430,  480,  113,  120,  161,  119,   74,
										 /*   720 */   149,  148,  441,  441,  441,  152,  479,  113,  120,  161,
										  /*   730 */   119,   88,  432,  433,  434,  435,  441,  441,  149,  441,
										   /*   740 */   120,  161,  119,  441,   74,  441,  148,  110,  110,  441,
										    /*   750 */   149,  476,  113,  120,  161,  119,   74,  441,  148,  107,
										     /*   760 */   441,  441,  152,  134,  113,  120,  161,  119,  120,  161,
										      /*   770 */   119,  441,  459,  441,   74,  149,  148,  441,  441,  441,
										       /*   780 */   563,  512,  113,  120,  161,  119,   74,  149,  148,  441,
										        /*   790 */   152,  441,  441,  137,  113,  120,  161,  119,  441,   74,
											 /*   800 */   441,  148,  441,  441,  441,  149,  520,  113,  120,  161,
											  /*   810 */   119,   74,  441,  148,  441,  441,   88,  149,  522,  113,
											   /*   820 */   120,  161,  119,  441,  441,  120,  161,  119,  441,   74,
											    /*   830 */   149,  148,  111,  111,  441,  441,  519,  113,  120,  161,
											     /*   840 */   119,  441,  149,  441,  441,  441,   74,  152,  148,  441,
											      /*   850 */   441,  441,   88,  521,  113,  120,  161,  119,  441,  441,
											       /*   860 */   149,  120,  161,  119,  441,   74,  441,  148,  471,  441,
											        /*   870 */   441,  441,  518,  113,  120,  161,  119,  149,   74,  441,
												 /*   880 */   148,  441,  441,  152,  441,  517,  113,  120,  161,  119,
												  /*   890 */    74,  441,  148,  441,  441,  441,  149,  516,  113,  120,
												   /*   900 */   161,  119,  441,   74,  441,  148,  441,  441,  441,  149,
												    /*   910 */   515,  113,  120,  161,  119,   74,  441,  148,   89,  441,
												     /*   920 */   441,  149,  514,  113,  120,  161,  119,  120,  161,  119,
												      /*   930 */   441,   74,  441,  148,  149,  441,  441,  441,  150,  113,
												       /*   940 */   120,  161,  119,  441,  441,  441,  149,  441,   74,  152,
												        /*   950 */   148,  441,  441,  441,   90,  151,  113,  120,  161,  119,
													 /*   960 */   441,  441,  149,  120,  161,  119,  441,   74,  441,  148,
													  /*   970 */    64,   63,   62,   61,  136,  113,  120,  161,  119,  149,
													   /*   980 */    74,  441,  148,  351,  441,  152,  441,  135,  113,  120,
													    /*   990 */   161,  119,   88,   64,   63,   62,   61,  441,  149,  441,
													     /*  1000 */   441,  120,  161,  119,  441,  107,  392,   10,  475,  475,
													      /*  1010 */   441,  149,  441,  441,  120,  161,  119,  107,  474,   64,
													       /*  1020 */    63,   62,   61,  152,   87,  441,  120,  161,  119,   99,
													        /*  1030 */   447,  441,  391,  120,  161,  119,  152,  441,  120,  161,
														 /*  1040 */   119,  100,  441,  441,   64,   63,   62,   61,  152,  441,
														  /*  1050 */   120,  161,  119,  441,  441,  152,  101,  387,  441,   91,
														   /*  1060 */   152,  441,  441,  441,  103,  120,  161,  119,  120,  161,
														    /*  1070 */   119,   92,  152,  120,  161,  119,  441,  441,  441,  441,
														     /*  1080 */   120,  161,  119,  441,  441,  441,  441,  152,  441,   93,
														      /*  1090 */   152,  441,  441,  441,  104,  152,  441,  441,  120,  161,
														       /*  1100 */   119,  441,  152,  120,  161,  119,  441,   94,  441,  441,
														        /*  1110 */   441,  441,  441,  105,  441,  441,  120,  161,  119,   95,
															 /*  1120 */   152,  441,  120,  161,  119,  152,   96,  441,  120,  161,
															  /*  1130 */   119,   97,  441,  441,  441,  120,  161,  119,  152,  441,
															   /*  1140 */   120,  161,  119,  543,  152,  441,  441,  441,  441,  441,
															    /*  1150 */   152,  441,  120,  161,  119,  441,  441,  152,  542,  441,
															     /*  1160 */   441,  541,  152,  441,  441,  441,  540,  120,  161,  119,
															      /*  1170 */   120,  161,  119,  115,  152,  120,  161,  119,   64,   63,
															       /*  1180 */    62,   61,  120,  161,  119,   64,   63,   62,   61,  152,
															        /*  1190 */   441,  116,  152,  441,  441,  441,  441,  152,  441,   53,
																 /*  1200 */   120,  161,  119,  441,  152,  441,   56,  441,  441,  441,
																  /*  1210 */   441,  441,  441,  441,  441,  441,  441,  441,  441,  441,
																   /*  1220 */   441,  441,  152,
};
static const YYCODETYPE yy_lookahead[] = {
	 /*     0 */     0,  110,  111,  112,  131,   99,  100,  101,  103,  103,
	  /*    10 */    10,  110,  111,  112,  108,  109,  110,  111,  112,  103,
	   /*    20 */    20,   21,   22,  102,   24,   10,  105,  106,   28,    4,
	    /*    30 */     5,    6,    7,   33,   34,   35,   36,   37,  132,   39,
	     /*    40 */    40,   41,   42,   28,   44,   45,  110,  111,  112,   49,
	      /*    50 */    50,   51,   52,   53,   54,   55,   56,   57,   58,   59,
	       /*    60 */    60,   61,   62,    0,    4,    5,    6,    7,    8,  104,
	        /*    70 */   101,   25,  103,   10,  110,  111,  112,  108,  109,  110,
		 /*    80 */   111,  112,  103,   20,   21,   22,   17,   24,  110,  111,
		  /*    90 */   112,   28,   26,   27,   25,  123,   33,   34,   35,   36,
		   /*   100 */    37,  132,   39,   40,   41,   42,   12,   44,   45,  130,
		    /*   110 */     2,  125,   49,   50,   51,   52,   53,   54,   55,   56,
		     /*   120 */    57,   58,   59,   60,   61,   62,    1,    2,    2,    4,
		      /*   130 */     5,   29,   30,   31,   32,   26,   27,   12,  126,    1,
		       /*   140 */    15,  102,    4,    5,  105,  106,   38,   81,    0,   24,
		        /*   150 */    12,   26,   27,   15,   88,  113,   31,   32,   10,    1,
			 /*   160 */     2,  113,    4,    5,   38,   19,  127,  128,  129,    1,
			  /*   170 */    12,   17,    1,   15,   80,    4,    5,   48,   20,   21,
			   /*   180 */    22,   16,   88,   12,   46,   47,   15,    3,   63,   31,
			    /*   190 */    32,   15,    1,    2,   43,    4,    5,   88,    4,    5,
			     /*   200 */     6,    7,   40,   12,   40,   80,   15,   82,   83,   84,
			      /*   210 */    85,   17,   13,   88,   89,   90,   91,   92,   80,   25,
			       /*   220 */    41,   63,   31,   32,  101,   96,   88,   89,   90,   91,
			        /*   230 */    92,    4,    5,  110,  111,  112,   41,  114,   80,   47,
				 /*   240 */    82,   83,   84,   85,  121,  122,   88,   89,   90,   91,
				  /*   250 */    92,   80,   17,    1,   63,  132,    4,    5,   25,   88,
				   /*   260 */    89,   90,   91,   92,   12,   26,   27,   15,   94,   95,
				    /*   270 */    86,   80,   17,   82,   83,   84,   85,   26,   27,   88,
				     /*   280 */    89,   90,   91,   92,    2,    3,    4,    5,    6,    7,
				      /*   290 */    73,    4,    5,    6,    7,    6,    7,   78,   16,   77,
				       /*   300 */    79,    2,    3,    4,    5,    6,    7,   25,    4,    5,
				        /*   310 */     6,    7,   78,   31,   32,    1,   17,   38,    4,    5,
					 /*   320 */    38,   17,   35,    3,   25,    3,   12,    3,    3,   15,
					  /*   330 */    31,   32,   80,    3,   20,   21,   22,   38,   24,    3,
					   /*   340 */    88,   89,   90,   91,   92,   98,   99,  100,   66,   67,
					    /*   350 */    93,  104,   75,   25,   15,   15,   74,   15,   76,   77,
					     /*   360 */    78,   17,  115,   28,   12,   66,   67,  120,   87,   28,
					      /*   370 */     3,   28,   11,   74,  133,   76,   77,   78,    2,    3,
					       /*   380 */     4,    5,    6,    7,   63,   64,   65,   66,   67,   68,
					        /*   390 */    69,   70,   71,   72,   80,  133,  133,    4,    5,    6,
						 /*   400 */     7,   25,   88,   89,   90,   91,   92,   31,   32,    1,
						  /*   410 */    17,  133,  133,  133,   38,  133,  133,  133,   25,  133,
						   /*   420 */    12,  133,   14,  133,  133,  133,   18,  133,   20,   21,
						    /*   430 */    22,   23,   24,  133,   26,   27,  133,   29,   30,   31,
						     /*   440 */    32,  133,   66,   67,    1,  133,  133,    4,    5,  133,
						      /*   450 */    74,  133,   76,   77,   78,   12,  133,  133,   15,  133,
						       /*   460 */   133,  133,  133,   20,   21,   22,    1,    2,  133,    4,
						        /*   470 */     5,    1,    2,  133,    4,    5,  133,   12,  133,   48,
							 /*   480 */    15,  133,   12,  133,  133,   15,  133,    1,    2,  133,
							  /*   490 */     4,    5,  133,    1,  133,  133,    4,    5,   12,  133,
							   /*   500 */   133,   15,  133,   38,   12,  101,    1,   15,  133,    4,
							    /*   510 */     5,  133,  133,  133,  110,  111,  112,   12,   87,  133,
							     /*   520 */    15,  117,  133,   80,   93,  133,  133,   96,  124,  133,
							      /*   530 */   126,   88,   89,   90,   91,   92,  132,  101,    4,    5,
							       /*   540 */     6,    7,  133,  133,  133,   80,  110,  111,  112,  133,
							        /*   550 */    80,  133,  133,   88,   89,   90,   91,   92,   88,   89,
								 /*   560 */    90,   91,   92,  133,  133,  133,   80,  133,  132,   35,
								  /*   570 */   133,  133,   80,  133,   88,   89,   90,   91,   92,    2,
								   /*   580 */    88,   89,   90,   91,   92,   80,  133,   20,   21,   22,
								    /*   590 */   133,  133,  101,   88,   89,   90,   91,   92,  133,  133,
								     /*   600 */   133,  110,  111,  112,   97,   98,   99,  100,   31,   32,
								      /*   610 */   133,  104,    4,    5,    6,    7,   49,   50,   51,   52,
								       /*   620 */    53,   54,  115,  132,  133,   48,  119,  120,   97,   98,
								        /*   630 */    99,  100,  133,   25,  101,  104,  103,  133,  133,  133,
									 /*   640 */    63,  108,  109,  110,  111,  112,  115,  101,  133,  103,
									  /*   650 */   133,  120,    2,  133,  108,  109,  110,  111,  112,   82,
									   /*   660 */    83,   84,   85,  133,  101,  132,  103,    4,    5,    6,
									    /*   670 */     7,  108,  109,  110,  111,  112,  133,  101,  132,  103,
									     /*   680 */    17,   31,   32,  133,  108,  109,  110,  111,  112,  101,
									      /*   690 */   133,  103,  133,  133,  101,  132,  108,  109,  110,  111,
									       /*   700 */   112,  133,  133,  110,  111,  112,  133,  101,  132,  103,
									        /*   710 */   133,  133,  133,   63,  108,  109,  110,  111,  112,  101,
										 /*   720 */   132,  103,  133,  133,  133,  132,  108,  109,  110,  111,
										  /*   730 */   112,  101,   82,   83,   84,   85,  133,  133,  132,  133,
										   /*   740 */   110,  111,  112,  133,  101,  133,  103,  117,  118,  133,
										    /*   750 */   132,  108,  109,  110,  111,  112,  101,  133,  103,  101,
										     /*   760 */   133,  133,  132,  108,  109,  110,  111,  112,  110,  111,
										      /*   770 */   112,  133,  114,  133,  101,  132,  103,  133,  133,  133,
										       /*   780 */   122,  108,  109,  110,  111,  112,  101,  132,  103,  133,
										        /*   790 */   132,  133,  133,  108,  109,  110,  111,  112,  133,  101,
											 /*   800 */   133,  103,  133,  133,  133,  132,  108,  109,  110,  111,
											  /*   810 */   112,  101,  133,  103,  133,  133,  101,  132,  108,  109,
											   /*   820 */   110,  111,  112,  133,  133,  110,  111,  112,  133,  101,
											    /*   830 */   132,  103,  117,  118,  133,  133,  108,  109,  110,  111,
											     /*   840 */   112,  133,  132,  133,  133,  133,  101,  132,  103,  133,
											      /*   850 */   133,  133,  101,  108,  109,  110,  111,  112,  133,  133,
											       /*   860 */   132,  110,  111,  112,  133,  101,  133,  103,  117,  133,
											        /*   870 */   133,  133,  108,  109,  110,  111,  112,  132,  101,  133,
												 /*   880 */   103,  133,  133,  132,  133,  108,  109,  110,  111,  112,
												  /*   890 */   101,  133,  103,  133,  133,  133,  132,  108,  109,  110,
												   /*   900 */   111,  112,  133,  101,  133,  103,  133,  133,  133,  132,
												    /*   910 */   108,  109,  110,  111,  112,  101,  133,  103,  101,  133,
												     /*   920 */   133,  132,  108,  109,  110,  111,  112,  110,  111,  112,
												      /*   930 */   133,  101,  133,  103,  132,  133,  133,  133,  108,  109,
												       /*   940 */   110,  111,  112,  133,  133,  133,  132,  133,  101,  132,
												        /*   950 */   103,  133,  133,  133,  101,  108,  109,  110,  111,  112,
													 /*   960 */   133,  133,  132,  110,  111,  112,  133,  101,  133,  103,
													  /*   970 */     4,    5,    6,    7,  108,  109,  110,  111,  112,  132,
													   /*   980 */   101,  133,  103,   17,  133,  132,  133,  108,  109,  110,
													    /*   990 */   111,  112,  101,    4,    5,    6,    7,  133,  132,  133,
													     /*  1000 */   133,  110,  111,  112,  133,  101,   17,  116,  117,  118,
													      /*  1010 */   133,  132,  133,  133,  110,  111,  112,  101,  114,    4,
													       /*  1020 */     5,    6,    7,  132,  101,  133,  110,  111,  112,  101,
													        /*  1030 */   114,  133,   17,  110,  111,  112,  132,  133,  110,  111,
														 /*  1040 */   112,  101,  133,  133,    4,    5,    6,    7,  132,  133,
														  /*  1050 */   110,  111,  112,  133,  133,  132,  101,   17,  133,  101,
														   /*  1060 */   132,  133,  133,  133,  101,  110,  111,  112,  110,  111,
														    /*  1070 */   112,  101,  132,  110,  111,  112,  133,  133,  133,  133,
														     /*  1080 */   110,  111,  112,  133,  133,  133,  133,  132,  133,  101,
														      /*  1090 */   132,  133,  133,  133,  101,  132,  133,  133,  110,  111,
														       /*  1100 */   112,  133,  132,  110,  111,  112,  133,  101,  133,  133,
														        /*  1110 */   133,  133,  133,  101,  133,  133,  110,  111,  112,  101,
															 /*  1120 */   132,  133,  110,  111,  112,  132,  101,  133,  110,  111,
															  /*  1130 */   112,  101,  133,  133,  133,  110,  111,  112,  132,  133,
															   /*  1140 */   110,  111,  112,  101,  132,  133,  133,  133,  133,  133,
															    /*  1150 */   132,  133,  110,  111,  112,  133,  133,  132,  101,  133,
															     /*  1160 */   133,  101,  132,  133,  133,  133,  101,  110,  111,  112,
															      /*  1170 */   110,  111,  112,  101,  132,  110,  111,  112,    4,    5,
															       /*  1180 */     6,    7,  110,  111,  112,    4,    5,    6,    7,  132,
															        /*  1190 */   133,  101,  132,  133,  133,  133,  133,  132,  133,   25,
																 /*  1200 */   110,  111,  112,  133,  132,  133,   25,  133,  133,  133,
																  /*  1210 */   133,  133,  133,  133,  133,  133,  133,  133,  133,  133,
																   /*  1220 */   133,  133,  132,  133,  133,  133,  133,  133,  133,  133,
																    /*  1230 */   133,  133,  133,  133,  133,  133,  133,  133,  133,  133,
																     /*  1240 */   133,  133,  133,  133,  133,  133,  133,  133,  133,  133,
																      /*  1250 */   133,  133,  133,  133,  133,  133,  133,  133,  133,  133,
																       /*  1260 */   133,  133,  133,  133,  133,  133,  133,  133,  133,  133,
																        /*  1270 */   133,  133,  133,  133,  133,  133,  133,  133,  133,  133,
																	 /*  1280 */   133,  133,  133,   97,   97,   97,   97,   97,   97,   97,
																	  /*  1290 */    97,   97,   97,   97,   97,   97,   97,   97,   97,   97,
																	   /*  1300 */    97,   97,   97,   97,   97,   97,   97,   97,   97,   97,
																	    /*  1310 */    97,   97,   97,   97,   97,   97,   97,   97,   97,   97,
};
#define YY_SHIFT_COUNT    (163)
#define YY_SHIFT_MIN      (0)
#define YY_SHIFT_MAX      (1181)
static const unsigned short int yy_shift_ofst[] = {
	 /*     0 */   408,  125,  158,  191,  191,  191,  191,  191,  191,  191,
	  /*    10 */   191,  191,  191,  191,  191,  191,  191,  191,  191,  191,
	   /*    20 */   191,  191,  191,  191,  191,  191,  191,  314,  138,  171,
	    /*    30 */   314,  408,  465,  465,    0,   63,  408,  252,  171,  252,
	     /*    40 */   443,  443,  443,  470,  486,  171,  171,  171,  171,  171,
	      /*    50 */   171,  492,  171,  171,  505,  171,  171,  171,  171,  171,
	       /*    60 */   171,  171,  171,  171,  171,  567,   94,   94,   94,   94,
	        /*    70 */    94,  577,  282,  299,  376,  650,  650,  102,   46, 1223,
		 /*    80 */  1223, 1223, 1223,  321,  321,  194,  393,  304,   60,  287,
		  /*    90 */   534,  663,  608,  966, 1174,  989, 1181, 1015, 1040,   25,
		   /*   100 */    25,   25,  431,   25,   25,   25,   66,   25,  109,   15,
		    /*   110 */   108,  126,   69,  227,  174,  289,  289,  239,  251,  184,
		     /*   120 */   129,  148,  146,  168,  154,  165,  176,  151,  162,  164,
		      /*   130 */   179,  195,  192,  199,  235,  233,  217,  255,  219,  222,
		       /*   140 */   221,  234,  320,  322,  324,  279,  325,  330,  336,  257,
		        /*   150 */   277,  328,  257,  339,  340,  342,  344,  335,  341,  343,
			 /*   160 */   352,  281,  367,  361,
};
#define YY_REDUCE_COUNT (82)
#define YY_REDUCE_MIN   (-127)
#define YY_REDUCE_MAX   (1090)
static const short yy_reduce_ofst[] = {
	 /*     0 */   507,  -94,  -31,  533,  546,  563,  576,  588,  606,  618,
	  /*    10 */   643,  655,  673,  685,  698,  710,  728,  745,  764,  777,
	   /*    20 */   789,  802,  814,  830,  847,  866,  879,  123,  891,  404,
	    /*    30 */   658,  531,  630,  715,   39,   39,  247,  904,  751,  916,
	     /*    40 */   436,  491,  593,  817,  853,  923,  928,  940,  955,  958,
	      /*    50 */   963,  970,  988,  993, 1006, 1012, 1018, 1025, 1030, 1042,
	       /*    60 */  1057, 1060, 1065, 1072, 1090,  -79, -109,  -99,  -64,  -36,
	        /*    70 */   -22,  -21, -127, -127, -127,  -95,  -84,  -35,  -28,  -14,
		 /*    80 */    42,   48,   12,
};
static const YYACTIONTYPE yy_default[] = {
	 /*     0 */   445,  439,  439,  439,  439,  439,  439,  439,  439,  439,
	  /*    10 */   439,  439,  439,  439,  439,  439,  439,  439,  439,  439,
	   /*    20 */   439,  439,  439,  439,  439,  439,  439,  439,  469,  570,
	    /*    30 */   439,  445,  574,  481,  575,  575,  445,  439,  439,  439,
	     /*    40 */   439,  439,  439,  439,  439,  439,  439,  439,  473,  439,
	      /*    50 */   439,  439,  439,  439,  439,  439,  439,  439,  439,  439,
	       /*    60 */   439,  439,  439,  439,  439,  439,  439,  439,  439,  439,
	        /*    70 */   439,  439,  439,  439,  439,  439,  439,  439,  451,  466,
		 /*    80 */   503,  503,  570,  464,  489,  439,  439,  439,  467,  439,
		  /*    90 */   439,  439,  439,  439,  439,  439,  439,  439,  439,  484,
		   /*   100 */   482,  472,  455,  507,  506,  505,  439,  560,  439,  439,
		    /*   110 */   439,  439,  439,  582,  439,  539,  538,  534,  439,  527,
		     /*   120 */   524,  439,  439,  439,  439,  439,  439,  487,  439,  439,
		      /*   130 */   439,  439,  439,  439,  439,  439,  439,  439,  439,  439,
		       /*   140 */   439,  439,  439,  439,  439,  439,  439,  439,  439,  586,
		        /*   150 */   439,  439,  439,  439,  439,  439,  439,  439,  439,  439,
			 /*   160 */   439,  595,  439,  439,
};
/********** End of lemon-generated parsing tables *****************************/

/* The next table maps tokens (terminal symbols) into fallback tokens.  
 * ** If a construct like the following:
 * ** 
 * **      %fallback ID X Y Z.
 * **
 * ** appears in the grammar, then ID becomes a fallback token for X, Y,
 * ** and Z.  Whenever one of the tokens X, Y, or Z is input to the parser
 * ** but it does not parse, the type of the token is changed to ID and
 * ** the parse is retried before an error is thrown.
 * **
 * ** This feature can be used, for example, to cause some keywords in a language
 * ** to revert to identifiers if they keyword does not apply in the context where
 * ** it appears.
 * */
#ifdef YYFALLBACK
static const YYCODETYPE yyFallback[] = {
	    0,  /*          $ => nothing */
	        0,  /*         ID => nothing */
		    1,  /*     EDGEPT => ID */
		        0,  /*         OF => nothing */
			    0,  /*       PLUS => nothing */
			        0,  /*      MINUS => nothing */
				    0,  /*       STAR => nothing */
				        0,  /*      SLASH => nothing */
					    0,  /*    PERCENT => nothing */
					        0,  /*     UMINUS => nothing */
						    0,  /*        EOL => nothing */
						        0,  /*     ASSIGN => nothing */
							    0,  /*  PLACENAME => nothing */
							        0,  /*      COLON => nothing */
								    0,  /*     ASSERT => nothing */
								        0,  /*         LP => nothing */
									    0,  /*         EQ => nothing */
									        0,  /*         RP => nothing */
										    0,  /*     DEFINE => nothing */
										        0,  /*  CODEBLOCK => nothing */
											    0,  /*       FILL => nothing */
											        0,  /*      COLOR => nothing */
												    0,  /*  THICKNESS => nothing */
												        0,  /*      PRINT => nothing */
													    0,  /*     STRING => nothing */
													        0,  /*      COMMA => nothing */
														    0,  /*  CLASSNAME => nothing */
														        0,  /*         LB => nothing */
															    0,  /*         RB => nothing */
															        0,  /*         UP => nothing */
																    0,  /*       DOWN => nothing */
																        0,  /*       LEFT => nothing */
																	    0,  /*      RIGHT => nothing */
																	        0,  /*      CLOSE => nothing */
																		    0,  /*       CHOP => nothing */
																		        0,  /*       FROM => nothing */
																			    0,  /*         TO => nothing */
																			        0,  /*       THEN => nothing */
																				    0,  /*    HEADING => nothing */
																				        0,  /*         GO => nothing */
																					    0,  /*         AT => nothing */
																					        0,  /*       WITH => nothing */
																						    0,  /*       SAME => nothing */
																						        0,  /*         AS => nothing */
																							    0,  /*        FIT => nothing */
																							        0,  /*     BEHIND => nothing */
																								    0,  /*      UNTIL => nothing */
																								        0,  /*       EVEN => nothing */
																									    0,  /*      DOT_E => nothing */
																									        0,  /*     HEIGHT => nothing */
																										    0,  /*      WIDTH => nothing */
																										        0,  /*     RADIUS => nothing */
																											    0,  /*   DIAMETER => nothing */
																											        0,  /*     DOTTED => nothing */
																												    0,  /*     DASHED => nothing */
																												        0,  /*         CW => nothing */
																													    0,  /*        CCW => nothing */
																													        0,  /*     LARROW => nothing */
																														    0,  /*     RARROW => nothing */
																														        0,  /*    LRARROW => nothing */
																															    0,  /*      INVIS => nothing */
																															        0,  /*      THICK => nothing */
																																    0,  /*       THIN => nothing */
																																        0,  /*     CENTER => nothing */
																																	    0,  /*      LJUST => nothing */
																																	        0,  /*      RJUST => nothing */
																																		    0,  /*      ABOVE => nothing */
																																		        0,  /*      BELOW => nothing */
																																			    0,  /*     ITALIC => nothing */
																																			        0,  /*       BOLD => nothing */
																																				    0,  /*    ALIGNED => nothing */
																																				        0,  /*        BIG => nothing */
																																					    0,  /*      SMALL => nothing */
																																					        0,  /*        AND => nothing */
																																						    0,  /*         LT => nothing */
																																						        0,  /*         GT => nothing */
																																							    0,  /*         ON => nothing */
																																							        0,  /*        WAY => nothing */
																																								    0,  /*    BETWEEN => nothing */
																																								        0,  /*        THE => nothing */
																																									    0,  /*        NTH => nothing */
																																									        0,  /*     VERTEX => nothing */
																																										    0,  /*        TOP => nothing */
																																										        0,  /*     BOTTOM => nothing */
																																											    0,  /*      START => nothing */
																																											        0,  /*        END => nothing */
																																												    0,  /*         IN => nothing */
																																												        0,  /*      DOT_U => nothing */
																																													    0,  /*       LAST => nothing */
																																													        0,  /*     NUMBER => nothing */
																																														    0,  /*      FUNC1 => nothing */
																																														        0,  /*      FUNC2 => nothing */
																																															    0,  /*       DIST => nothing */
																																															        0,  /*     DOT_XY => nothing */
																																																    0,  /*          X => nothing */
																																																        0,  /*          Y => nothing */
																																																	    0,  /*      DOT_L => nothing */
};
#endif /* YYFALLBACK */

/* The following structure represents a single element of the
 * ** parser's stack.  Information stored includes:
 * **
 * **   +  The state number for the parser at this level of the stack.
 * **
 * **   +  The value of the token stored at this level of the stack.
 * **      (In other words, the "major" token.)
 * **
 * **   +  The semantic value stored at this level of the stack.  This is
 * **      the information used by the action routines in the grammar.
 * **      It is sometimes called the "minor" token.
 * **
 * ** After the "shift" half of a SHIFTREDUCE action, the stateno field
 * ** actually contains the reduce action for the second half of the
 * ** SHIFTREDUCE.
 * */
struct yyStackEntry {
	  YYACTIONTYPE stateno;  /* The state-number, or reduce action in SHIFTREDUCE */
	    YYCODETYPE major;      /* The major token value.  This is the code
				                               ** number for the token at this stack level */
	      YYMINORTYPE minor;     /* The user-supplied minor token value.  This
					                         ** is the value of the token  */
};
typedef struct yyStackEntry yyStackEntry;

/* The state of the parser is completely contained in an instance of
 * ** the following structure */
struct yyParser {
	  yyStackEntry *yytos;          /* Pointer to top element of the stack */
#ifdef YYTRACKMAXSTACKDEPTH
	    int yyhwm;                    /* High-water mark of the stack */
#endif
#ifndef YYNOERRORRECOVERY
	      int yyerrcnt;                 /* Shifts left before out of the error */
#endif
	        pik_parserARG_SDECL                /* A place to hold %extra_argument */
			  pik_parserCTX_SDECL                /* A place to hold %extra_context */
#if YYSTACKDEPTH<=0
			    int yystksz;                  /* Current side of the stack */
		  yyStackEntry *yystack;        /* The parser's stack */
		    yyStackEntry yystk0;          /* First stack entry */
#else
		      yyStackEntry yystack[YYSTACKDEPTH];  /* The parser's stack */
		        yyStackEntry *yystackEnd;            /* Last entry in the stack */
#endif
};
typedef struct yyParser yyParser;

#ifndef NDEBUG
#include <stdio.h>
#include <assert.h>
static FILE *yyTraceFILE = 0;
static char *yyTracePrompt = 0;
#endif /* NDEBUG */

#ifndef NDEBUG
/* 
 * ** Turn parser tracing on by giving a stream to which to write the trace
 * ** and a prompt to preface each trace message.  Tracing is turned off
 * ** by making either argument NULL 
 * **
 * ** Inputs:
 * ** <ul>
 * ** <li> A FILE* to which trace output should be written.
 * **      If NULL, then tracing is turned off.
 * ** <li> A prefix string written at the beginning of every
 * **      line of trace output.  If NULL, then tracing is
 * **      turned off.
 * ** </ul>
 * **
 * ** Outputs:
 * ** None.
 * */
void pik_parserTrace(FILE *TraceFILE, char *zTracePrompt){
	  yyTraceFILE = TraceFILE;
	    yyTracePrompt = zTracePrompt;
	      if( yyTraceFILE==0 ) yyTracePrompt = 0;
	        else if( yyTracePrompt==0 ) yyTraceFILE = 0;
}
#endif /* NDEBUG */

#if defined(YYCOVERAGE) || !defined(NDEBUG)
/* For tracing shifts, the names of all terminals and nonterminals
 * ** are required.  The following table supplies these names */
static const char *const yyTokenName[] = { 
	  /*    0 */ "$",
	    /*    1 */ "ID",
	      /*    2 */ "EDGEPT",
	        /*    3 */ "OF",
		  /*    4 */ "PLUS",
		    /*    5 */ "MINUS",
		      /*    6 */ "STAR",
		        /*    7 */ "SLASH",
			  /*    8 */ "PERCENT",
			    /*    9 */ "UMINUS",
			      /*   10 */ "EOL",
			        /*   11 */ "ASSIGN",
				  /*   12 */ "PLACENAME",
				    /*   13 */ "COLON",
				      /*   14 */ "ASSERT",
				        /*   15 */ "LP",
					  /*   16 */ "EQ",
					    /*   17 */ "RP",
					      /*   18 */ "DEFINE",
					        /*   19 */ "CODEBLOCK",
						  /*   20 */ "FILL",
						    /*   21 */ "COLOR",
						      /*   22 */ "THICKNESS",
						        /*   23 */ "PRINT",
							  /*   24 */ "STRING",
							    /*   25 */ "COMMA",
							      /*   26 */ "CLASSNAME",
							        /*   27 */ "LB",
								  /*   28 */ "RB",
								    /*   29 */ "UP",
								      /*   30 */ "DOWN",
								        /*   31 */ "LEFT",
									  /*   32 */ "RIGHT",
									    /*   33 */ "CLOSE",
									      /*   34 */ "CHOP",
									        /*   35 */ "FROM",
										  /*   36 */ "TO",
										    /*   37 */ "THEN",
										      /*   38 */ "HEADING",
										        /*   39 */ "GO",
											  /*   40 */ "AT",
											    /*   41 */ "WITH",
											      /*   42 */ "SAME",
											        /*   43 */ "AS",
												  /*   44 */ "FIT",
												    /*   45 */ "BEHIND",
												      /*   46 */ "UNTIL",
												        /*   47 */ "EVEN",
													  /*   48 */ "DOT_E",
													    /*   49 */ "HEIGHT",
													      /*   50 */ "WIDTH",
													        /*   51 */ "RADIUS",
														  /*   52 */ "DIAMETER",
														    /*   53 */ "DOTTED",
														      /*   54 */ "DASHED",
														        /*   55 */ "CW",
															  /*   56 */ "CCW",
															    /*   57 */ "LARROW",
															      /*   58 */ "RARROW",
															        /*   59 */ "LRARROW",
																  /*   60 */ "INVIS",
																    /*   61 */ "THICK",
																      /*   62 */ "THIN",
																        /*   63 */ "CENTER",
																	  /*   64 */ "LJUST",
																	    /*   65 */ "RJUST",
																	      /*   66 */ "ABOVE",
																	        /*   67 */ "BELOW",
																		  /*   68 */ "ITALIC",
																		    /*   69 */ "BOLD",
																		      /*   70 */ "ALIGNED",
																		        /*   71 */ "BIG",
																			  /*   72 */ "SMALL",
																			    /*   73 */ "AND",
																			      /*   74 */ "LT",
																			        /*   75 */ "GT",
																				  /*   76 */ "ON",
																				    /*   77 */ "WAY",
																				      /*   78 */ "BETWEEN",
																				        /*   79 */ "THE",
																					  /*   80 */ "NTH",
																					    /*   81 */ "VERTEX",
																					      /*   82 */ "TOP",
																					        /*   83 */ "BOTTOM",
																						  /*   84 */ "START",
																						    /*   85 */ "END",
																						      /*   86 */ "IN",
																						        /*   87 */ "DOT_U",
																							  /*   88 */ "LAST",
																							    /*   89 */ "NUMBER",
																							      /*   90 */ "FUNC1",
																							        /*   91 */ "FUNC2",
																								  /*   92 */ "DIST",
																								    /*   93 */ "DOT_XY",
																								      /*   94 */ "X",
																								        /*   95 */ "Y",
																									  /*   96 */ "DOT_L",
																									    /*   97 */ "statement_list",
																									      /*   98 */ "statement",
																									        /*   99 */ "unnamed_statement",
																										  /*  100 */ "basetype",
																										    /*  101 */ "expr",
																										      /*  102 */ "numproperty",
																										        /*  103 */ "edge",
																											  /*  104 */ "direction",
																											    /*  105 */ "dashproperty",
																											      /*  106 */ "colorproperty",
																											        /*  107 */ "locproperty",
																												  /*  108 */ "position",
																												    /*  109 */ "place",
																												      /*  110 */ "object",
																												        /*  111 */ "objectname",
																													  /*  112 */ "nth",
																													    /*  113 */ "textposition",
																													      /*  114 */ "rvalue",
																													        /*  115 */ "lvalue",
																														  /*  116 */ "even",
																														    /*  117 */ "relexpr",
																														      /*  118 */ "optrelexpr",
																														        /*  119 */ "document",
																															  /*  120 */ "print",
																															    /*  121 */ "prlist",
																															      /*  122 */ "pritem",
																															        /*  123 */ "prsep",
																																  /*  124 */ "attribute_list",
																																    /*  125 */ "savelist",
																																      /*  126 */ "alist",
																																        /*  127 */ "attribute",
																																	  /*  128 */ "go",
																																	    /*  129 */ "boolproperty",
																																	      /*  130 */ "withclause",
																																	        /*  131 */ "between",
																																		  /*  132 */ "place2",
};
#endif /* defined(YYCOVERAGE) || !defined(NDEBUG) */

#ifndef NDEBUG
/* For tracing reduce actions, the names of all rules are required.
 * */
static const char *const yyRuleName[] = {
	 /*   0 */ "document ::= statement_list",
	  /*   1 */ "statement_list ::= statement",
	   /*   2 */ "statement_list ::= statement_list EOL statement",
	    /*   3 */ "statement ::=",
	     /*   4 */ "statement ::= direction",
	      /*   5 */ "statement ::= lvalue ASSIGN rvalue",
	       /*   6 */ "statement ::= PLACENAME COLON unnamed_statement",
	        /*   7 */ "statement ::= PLACENAME COLON position",
		 /*   8 */ "statement ::= unnamed_statement",
		  /*   9 */ "statement ::= print prlist",
		   /*  10 */ "statement ::= ASSERT LP expr EQ expr RP",
		    /*  11 */ "statement ::= ASSERT LP position EQ position RP",
		     /*  12 */ "statement ::= DEFINE ID CODEBLOCK",
		      /*  13 */ "rvalue ::= PLACENAME",
		       /*  14 */ "pritem ::= FILL",
		        /*  15 */ "pritem ::= COLOR",
			 /*  16 */ "pritem ::= THICKNESS",
			  /*  17 */ "pritem ::= rvalue",
			   /*  18 */ "pritem ::= STRING",
			    /*  19 */ "prsep ::= COMMA",
			     /*  20 */ "unnamed_statement ::= basetype attribute_list",
			      /*  21 */ "basetype ::= CLASSNAME",
			       /*  22 */ "basetype ::= STRING textposition",
			        /*  23 */ "basetype ::= LB savelist statement_list RB",
				 /*  24 */ "savelist ::=",
				  /*  25 */ "relexpr ::= expr",
				   /*  26 */ "relexpr ::= expr PERCENT",
				    /*  27 */ "optrelexpr ::=",
				     /*  28 */ "attribute_list ::= relexpr alist",
				      /*  29 */ "attribute ::= numproperty relexpr",
				       /*  30 */ "attribute ::= dashproperty expr",
				        /*  31 */ "attribute ::= dashproperty",
					 /*  32 */ "attribute ::= colorproperty rvalue",
					  /*  33 */ "attribute ::= go direction optrelexpr",
					   /*  34 */ "attribute ::= go direction even position",
					    /*  35 */ "attribute ::= CLOSE",
					     /*  36 */ "attribute ::= CHOP",
					      /*  37 */ "attribute ::= FROM position",
					       /*  38 */ "attribute ::= TO position",
					        /*  39 */ "attribute ::= THEN",
						 /*  40 */ "attribute ::= THEN optrelexpr HEADING expr",
						  /*  41 */ "attribute ::= THEN optrelexpr EDGEPT",
						   /*  42 */ "attribute ::= GO optrelexpr HEADING expr",
						    /*  43 */ "attribute ::= GO optrelexpr EDGEPT",
						     /*  44 */ "attribute ::= AT position",
						      /*  45 */ "attribute ::= SAME",
						       /*  46 */ "attribute ::= SAME AS object",
						        /*  47 */ "attribute ::= STRING textposition",
							 /*  48 */ "attribute ::= FIT",
							  /*  49 */ "attribute ::= BEHIND object",
							   /*  50 */ "withclause ::= DOT_E edge AT position",
							    /*  51 */ "withclause ::= edge AT position",
							     /*  52 */ "numproperty ::= HEIGHT|WIDTH|RADIUS|DIAMETER|THICKNESS",
							      /*  53 */ "boolproperty ::= CW",
							       /*  54 */ "boolproperty ::= CCW",
							        /*  55 */ "boolproperty ::= LARROW",
								 /*  56 */ "boolproperty ::= RARROW",
								  /*  57 */ "boolproperty ::= LRARROW",
								   /*  58 */ "boolproperty ::= INVIS",
								    /*  59 */ "boolproperty ::= THICK",
								     /*  60 */ "boolproperty ::= THIN",
								      /*  61 */ "textposition ::=",
								       /*  62 */ "textposition ::= textposition CENTER|LJUST|RJUST|ABOVE|BELOW|ITALIC|BOLD|ALIGNED|BIG|SMALL",
								        /*  63 */ "position ::= expr COMMA expr",
									 /*  64 */ "position ::= place PLUS expr COMMA expr",
									  /*  65 */ "position ::= place MINUS expr COMMA expr",
									   /*  66 */ "position ::= place PLUS LP expr COMMA expr RP",
									    /*  67 */ "position ::= place MINUS LP expr COMMA expr RP",
									     /*  68 */ "position ::= LP position COMMA position RP",
									      /*  69 */ "position ::= LP position RP",
									       /*  70 */ "position ::= expr between position AND position",
									        /*  71 */ "position ::= expr LT position COMMA position GT",
										 /*  72 */ "position ::= expr ABOVE position",
										  /*  73 */ "position ::= expr BELOW position",
										   /*  74 */ "position ::= expr LEFT OF position",
										    /*  75 */ "position ::= expr RIGHT OF position",
										     /*  76 */ "position ::= expr ON HEADING EDGEPT OF position",
										      /*  77 */ "position ::= expr HEADING EDGEPT OF position",
										       /*  78 */ "position ::= expr EDGEPT OF position",
										        /*  79 */ "position ::= expr ON HEADING expr FROM position",
											 /*  80 */ "position ::= expr HEADING expr FROM position",
											  /*  81 */ "place ::= edge OF object",
											   /*  82 */ "place2 ::= object",
											    /*  83 */ "place2 ::= object DOT_E edge",
											     /*  84 */ "place2 ::= NTH VERTEX OF object",
											      /*  85 */ "object ::= nth",
											       /*  86 */ "object ::= nth OF|IN object",
											        /*  87 */ "objectname ::= PLACENAME",
												 /*  88 */ "objectname ::= objectname DOT_U PLACENAME",
												  /*  89 */ "nth ::= NTH CLASSNAME",
												   /*  90 */ "nth ::= NTH LAST CLASSNAME",
												    /*  91 */ "nth ::= LAST CLASSNAME",
												     /*  92 */ "nth ::= LAST",
												      /*  93 */ "nth ::= NTH LB RB",
												       /*  94 */ "nth ::= NTH LAST LB RB",
												        /*  95 */ "nth ::= LAST LB RB",
													 /*  96 */ "expr ::= expr PLUS expr",
													  /*  97 */ "expr ::= expr MINUS expr",
													   /*  98 */ "expr ::= expr STAR expr",
													    /*  99 */ "expr ::= expr SLASH expr",
													     /* 100 */ "expr ::= MINUS expr",
													      /* 101 */ "expr ::= PLUS expr",
													       /* 102 */ "expr ::= LP expr RP",
													        /* 103 */ "expr ::= LP FILL|COLOR|THICKNESS RP",
														 /* 104 */ "expr ::= NUMBER",
														  /* 105 */ "expr ::= ID",
														   /* 106 */ "expr ::= FUNC1 LP expr RP",
														    /* 107 */ "expr ::= FUNC2 LP expr COMMA expr RP",
														     /* 108 */ "expr ::= DIST LP position COMMA position RP",
														      /* 109 */ "expr ::= place2 DOT_XY X",
														       /* 110 */ "expr ::= place2 DOT_XY Y",
														        /* 111 */ "expr ::= object DOT_L numproperty",
															 /* 112 */ "expr ::= object DOT_L dashproperty",
															  /* 113 */ "expr ::= object DOT_L colorproperty",
															   /* 114 */ "lvalue ::= ID",
															    /* 115 */ "lvalue ::= FILL",
															     /* 116 */ "lvalue ::= COLOR",
															      /* 117 */ "lvalue ::= THICKNESS",
															       /* 118 */ "rvalue ::= expr",
															        /* 119 */ "print ::= PRINT",
																 /* 120 */ "prlist ::= pritem",
																  /* 121 */ "prlist ::= prlist prsep pritem",
																   /* 122 */ "direction ::= UP",
																    /* 123 */ "direction ::= DOWN",
																     /* 124 */ "direction ::= LEFT",
																      /* 125 */ "direction ::= RIGHT",
																       /* 126 */ "optrelexpr ::= relexpr",
																        /* 127 */ "attribute_list ::= alist",
																	 /* 128 */ "alist ::=",
																	  /* 129 */ "alist ::= alist attribute",
																	   /* 130 */ "attribute ::= boolproperty",
																	    /* 131 */ "attribute ::= WITH withclause",
																	     /* 132 */ "go ::= GO",
																	      /* 133 */ "go ::=",
																	       /* 134 */ "even ::= UNTIL EVEN WITH",
																	        /* 135 */ "even ::= EVEN WITH",
																		 /* 136 */ "dashproperty ::= DOTTED",
																		  /* 137 */ "dashproperty ::= DASHED",
																		   /* 138 */ "colorproperty ::= FILL",
																		    /* 139 */ "colorproperty ::= COLOR",
																		     /* 140 */ "position ::= place",
																		      /* 141 */ "between ::= WAY BETWEEN",
																		       /* 142 */ "between ::= BETWEEN",
																		        /* 143 */ "between ::= OF THE WAY BETWEEN",
																			 /* 144 */ "place ::= place2",
																			  /* 145 */ "edge ::= CENTER",
																			   /* 146 */ "edge ::= EDGEPT",
																			    /* 147 */ "edge ::= TOP",
																			     /* 148 */ "edge ::= BOTTOM",
																			      /* 149 */ "edge ::= START",
																			       /* 150 */ "edge ::= END",
																			        /* 151 */ "edge ::= RIGHT",
																				 /* 152 */ "edge ::= LEFT",
																				  /* 153 */ "object ::= objectname",
};
#endif /* NDEBUG */


#if YYSTACKDEPTH<=0
/*
 * ** Try to increase the size of the parser stack.  Return the number
 * ** of errors.  Return 0 on success.
 * */
static int yyGrowStack(yyParser *p){
	  int newSize;
	    int idx;
	      yyStackEntry *pNew;

	        newSize = p->yystksz*2 + 100;
		  idx = p->yytos ? (int)(p->yytos - p->yystack) : 0;
		    if( p->yystack==&p->yystk0 ){
			        pNew = malloc(newSize*sizeof(pNew[0]));
				    if( pNew ) pNew[0] = p->yystk0;
				      }else{
					          pNew = realloc(p->yystack, newSize*sizeof(pNew[0]));
						    }
		      if( pNew ){
			          p->yystack = pNew;
				      p->yytos = &p->yystack[idx];
#ifndef NDEBUG
				          if( yyTraceFILE ){
						        fprintf(yyTraceFILE,"%sStack grows from %d to %d entries.\n",
									              yyTracePrompt, p->yystksz, newSize);
							    }
#endif
					      p->yystksz = newSize;
					        }
		        return pNew==0; 
}
#endif

/* Datatype of the argument to the memory allocated passed as the
 * ** second argument to pik_parserAlloc() below.  This can be changed by
 * ** putting an appropriate #define in the %include section of the input
 * ** grammar.
 * */
#ifndef YYMALLOCARGTYPE
# define YYMALLOCARGTYPE size_t
#endif

/* Initialize a new parser that has already been allocated.
 * */
void pik_parserInit(void *yypRawParser pik_parserCTX_PDECL){
	  yyParser *yypParser = (yyParser*)yypRawParser;
	    pik_parserCTX_STORE
#ifdef YYTRACKMAXSTACKDEPTH
		      yypParser->yyhwm = 0;
#endif
#if YYSTACKDEPTH<=0
	      yypParser->yytos = NULL;
	        yypParser->yystack = NULL;
		  yypParser->yystksz = 0;
		    if( yyGrowStack(yypParser) ){
			        yypParser->yystack = &yypParser->yystk0;
				    yypParser->yystksz = 1;
				      }
#endif
#ifndef YYNOERRORRECOVERY
		      yypParser->yyerrcnt = -1;
#endif
		        yypParser->yytos = yypParser->yystack;
			  yypParser->yystack[0].stateno = 0;
			    yypParser->yystack[0].major = 0;
#if YYSTACKDEPTH>0
			      yypParser->yystackEnd = &yypParser->yystack[YYSTACKDEPTH-1];
#endif
}

#ifndef pik_parser_ENGINEALWAYSONSTACK
/* 
 * ** This function allocates a new parser.
 * ** The only argument is a pointer to a function which works like
 * ** malloc.
 * **
 * ** Inputs:
 * ** A pointer to the function used to allocate memory.
 * **
 * ** Outputs:
 * ** A pointer to a parser.  This pointer is used in subsequent calls
 * ** to pik_parser and pik_parserFree.
 * */
void *pik_parserAlloc(void *(*mallocProc)(YYMALLOCARGTYPE) pik_parserCTX_PDECL){
	  yyParser *yypParser;
	    yypParser = (yyParser*)(*mallocProc)( (YYMALLOCARGTYPE)sizeof(yyParser) );
	      if( yypParser ){
		          pik_parserCTX_STORE
				      pik_parserInit(yypParser pik_parserCTX_PARAM);
			    }
	        return (void*)yypParser;
}
#endif /* pik_parser_ENGINEALWAYSONSTACK */


/* The following function deletes the "minor type" or semantic value
 * ** associated with a symbol.  The symbol can be either a terminal
 * ** or nonterminal. "yymajor" is the symbol code, and "yypminor" is
 * ** a pointer to the value to be deleted.  The code used to do the 
 * ** deletions is derived from the %destructor and/or %token_destructor
 * ** directives of the input grammar.
 * */
static void yy_destructor(
		  yyParser *yypParser,    /* The parser */
		    YYCODETYPE yymajor,     /* Type code for object to destroy */
		      YYMINORTYPE *yypminor   /* The object to be destroyed */
		){
	  pik_parserARG_FETCH
		    pik_parserCTX_FETCH
		      switch( yymajor ){
			          /* Here is inserted the actions which take place when a
				   *     ** terminal or non-terminal is destroyed.  This can happen
				   *         ** when the symbol is popped from the stack during a
				   *             ** reduce or during error processing or when a parser is 
				   *                 ** being destroyed before it is finished parsing.
				   *                     **
				   *                         ** Note: during a reduce, the only symbols destroyed are those
				   *                             ** which appear on the RHS of the rule, but which are *not* used
				   *                                 ** inside the C code.
				   *                                     */
			      /********* Begin destructor definitions ***************************************/
			          case 97: /* statement_list */
					  {
#line 483 "pikchr.y"
						  pik_elist_free(p,(yypminor->yy191));
#line 1699 "pikchr.c"
					  }
					        break;
						    case 98: /* statement */
						    case 99: /* unnamed_statement */
						    case 100: /* basetype */
						{
#line 485 "pikchr.y"
							pik_elem_free(p,(yypminor->yy138));
#line 1708 "pikchr.c"
						}
						      break;
						      /********* End destructor definitions *****************************************/
						          default:  break;   /* If no destructor action specified: do nothing */
								      }
}

/*
 * ** Pop the parser's stack once.
 * **
 * ** If there is a destructor routine associated with the token which
 * ** is popped from the stack, then call it.
 * */
static void yy_pop_parser_stack(yyParser *pParser){
	  yyStackEntry *yytos;
	    assert( pParser->yytos!=0 );
	      assert( pParser->yytos > pParser->yystack );
	        yytos = pParser->yytos--;
#ifndef NDEBUG
		  if( yyTraceFILE ){
			      fprintf(yyTraceFILE,"%sPopping %s\n",
					            yyTracePrompt,
						          yyTokenName[yytos->major]);
			        }
#endif
		    yy_destructor(pParser, yytos->major, &yytos->minor);
}

/*
 * ** Clear all secondary memory allocations from the parser
 * */
void pik_parserFinalize(void *p){
	  yyParser *pParser = (yyParser*)p;
	    while( pParser->yytos>pParser->yystack ) yy_pop_parser_stack(pParser);
#if YYSTACKDEPTH<=0
	      if( pParser->yystack!=&pParser->yystk0 ) free(pParser->yystack);
#endif
}

#ifndef pik_parser_ENGINEALWAYSONSTACK
/* 
 * ** Deallocate and destroy a parser.  Destructors are called for
 * ** all stack elements before shutting the parser down.
 * **
 * ** If the YYPARSEFREENEVERNULL macro exists (for example because it
 * ** is defined in a %include section of the input grammar) then it is
 * ** assumed that the input pointer is never NULL.
 * */
void pik_parserFree(
		  void *p,                    /* The parser to be deleted */
		    void (*freeProc)(void*)     /* Function used to reclaim memory */
		){
#ifndef YYPARSEFREENEVERNULL
	  if( p==0 ) return;
#endif
	    pik_parserFinalize(p);
	      (*freeProc)(p);
}
#endif /* pik_parser_ENGINEALWAYSONSTACK */

/*
 * ** Return the peak depth of the stack for a parser.
 * */
#ifdef YYTRACKMAXSTACKDEPTH
int pik_parserStackPeak(void *p){
	  yyParser *pParser = (yyParser*)p;
	    return pParser->yyhwm;
}
#endif

/* This array of booleans keeps track of the parser statement
 * ** coverage.  The element yycoverage[X][Y] is set when the parser
 * ** is in state X and has a lookahead token Y.  In a well-tested
 * ** systems, every element of this matrix should end up being set.
 * */
#if defined(YYCOVERAGE)
static unsigned char yycoverage[YYNSTATE][YYNTOKEN];
#endif

/*
 * ** Write into out a description of every state/lookahead combination that
 * **
 * **   (1)  has not been used by the parser, and
 * **   (2)  is not a syntax error.
 * **
 * ** Return the number of missed state/lookahead combinations.
 * */
#if defined(YYCOVERAGE)
int pik_parserCoverage(FILE *out){
	  int stateno, iLookAhead, i;
	    int nMissed = 0;
	      for(stateno=0; stateno<YYNSTATE; stateno++){
		          i = yy_shift_ofst[stateno];
			      for(iLookAhead=0; iLookAhead<YYNTOKEN; iLookAhead++){
				            if( yy_lookahead[i+iLookAhead]!=iLookAhead ) continue;
					          if( yycoverage[stateno][iLookAhead]==0 ) nMissed++;
						        if( out ){
								        fprintf(out,"State %d lookahead %s %s\n", stateno,
											                yyTokenName[iLookAhead],
													                yycoverage[stateno][iLookAhead] ? "ok" : "missed");
									      }
							    }
			        }
	        return nMissed;
}
#endif

/*
 * ** Find the appropriate action for a parser given the terminal
 * ** look-ahead token iLookAhead.
 * */
static YYACTIONTYPE yy_find_shift_action(
		  YYCODETYPE iLookAhead,    /* The look-ahead token */
		    YYACTIONTYPE stateno      /* Current state number */
		){
	  int i;

	    if( stateno>YY_MAX_SHIFT ) return stateno;
	      assert( stateno <= YY_SHIFT_COUNT );
#if defined(YYCOVERAGE)
	        yycoverage[stateno][iLookAhead] = 1;
#endif
		  do{
			      i = yy_shift_ofst[stateno];
			          assert( i>=0 );
				      assert( i<=YY_ACTTAB_COUNT );
				          assert( i+YYNTOKEN<=(int)YY_NLOOKAHEAD );
					      assert( iLookAhead!=YYNOCODE );
					          assert( iLookAhead < YYNTOKEN );
						      i += iLookAhead;
						          assert( i<(int)YY_NLOOKAHEAD );
							      if( yy_lookahead[i]!=iLookAhead ){
#ifdef YYFALLBACK
								            YYCODETYPE iFallback;            /* Fallback token */
									          assert( iLookAhead<sizeof(yyFallback)/sizeof(yyFallback[0]) );
										        iFallback = yyFallback[iLookAhead];
											      if( iFallback!=0 ){
#ifndef NDEBUG
												              if( yyTraceFILE ){
														                fprintf(yyTraceFILE, "%sFALLBACK %s => %s\n",
																		             yyTracePrompt, yyTokenName[iLookAhead], yyTokenName[iFallback]);
																        }
#endif
													              assert( yyFallback[iFallback]==0 ); /* Fallback loop must terminate */
														              iLookAhead = iFallback;
															              continue;
																            }
#endif
#ifdef YYWILDCARD
											            {
													            int j = i - iLookAhead + YYWILDCARD;
														            assert( j<(int)(sizeof(yy_lookahead)/sizeof(yy_lookahead[0])) );
															            if( yy_lookahead[j]==YYWILDCARD && iLookAhead>0 ){
#ifndef NDEBUG
																	              if( yyTraceFILE ){
																			                  fprintf(yyTraceFILE, "%sWILDCARD %s => %s\n",
																							                 yyTracePrompt, yyTokenName[iLookAhead],
																									                yyTokenName[YYWILDCARD]);
																					            }
#endif /* NDEBUG */
																		                return yy_action[j];
																				        }
																          }
#endif /* YYWILDCARD */
												          return yy_default[stateno];
													      }else{
														            assert( i>=0 && i<(int)(sizeof(yy_action)/sizeof(yy_action[0])) );
															          return yy_action[i];
																      }
							        }while(1);
}

/*
 * ** Find the appropriate action for a parser given the non-terminal
 * ** look-ahead token iLookAhead.
 * */
static YYACTIONTYPE yy_find_reduce_action(
		  YYACTIONTYPE stateno,     /* Current state number */
		    YYCODETYPE iLookAhead     /* The look-ahead token */
		){
	  int i;
#ifdef YYERRORSYMBOL
	    if( stateno>YY_REDUCE_COUNT ){
		        return yy_default[stateno];
			  }
#else
	      assert( stateno<=YY_REDUCE_COUNT );
#endif
	        i = yy_reduce_ofst[stateno];
		  assert( iLookAhead!=YYNOCODE );
		    i += iLookAhead;
#ifdef YYERRORSYMBOL
		      if( i<0 || i>=YY_ACTTAB_COUNT || yy_lookahead[i]!=iLookAhead ){
			          return yy_default[stateno];
				    }
#else
		        assert( i>=0 && i<YY_ACTTAB_COUNT );
			  assert( yy_lookahead[i]==iLookAhead );
#endif
			    return yy_action[i];
}

/*
 * ** The following routine is called if the stack overflows.
 * */
static void yyStackOverflow(yyParser *yypParser){
	   pik_parserARG_FETCH
		      pik_parserCTX_FETCH
#ifndef NDEBUG
		         if( yyTraceFILE ){
				      fprintf(yyTraceFILE,"%sStack Overflow!\n",yyTracePrompt);
				         }
#endif
	      while( yypParser->yytos>yypParser->yystack ) yy_pop_parser_stack(yypParser);
	      /* Here code is inserted which will execute if the parser
	       *    ** stack every overflows */
	   /******** Begin %stack_overflow code ******************************************/
#line 517 "pikchr.y"

	     pik_error(p, 0, "parser stack overflow");
#line 1929 "pikchr.c"
	   /******** End %stack_overflow code ********************************************/
	      pik_parserARG_STORE /* Suppress warning about unused %extra_argument var */
		         pik_parserCTX_STORE
}

/*
 * ** Print tracing information for a SHIFT action
 * */
#ifndef NDEBUG
static void yyTraceShift(yyParser *yypParser, int yyNewState, const char *zTag){
	  if( yyTraceFILE ){
		      if( yyNewState<YYNSTATE ){
			            fprintf(yyTraceFILE,"%s%s '%s', go to state %d\n",
						             yyTracePrompt, zTag, yyTokenName[yypParser->yytos->major],
							              yyNewState);
				        }else{
						      fprintf(yyTraceFILE,"%s%s '%s', pending reduce %d\n",
								               yyTracePrompt, zTag, yyTokenName[yypParser->yytos->major],
									                yyNewState - YY_MIN_REDUCE);
						          }
		        }
}
#else
# define yyTraceShift(X,Y,Z)
#endif

/*
 * ** Perform a shift action.
 * */
static void yy_shift(
		  yyParser *yypParser,          /* The parser to be shifted */
		    YYACTIONTYPE yyNewState,      /* The new state to shift in */
		      YYCODETYPE yyMajor,           /* The major token to shift in */
		        pik_parserTOKENTYPE yyMinor        /* The minor token to shift in */
		){
	  yyStackEntry *yytos;
	    yypParser->yytos++;
#ifdef YYTRACKMAXSTACKDEPTH
	      if( (int)(yypParser->yytos - yypParser->yystack)>yypParser->yyhwm ){
		          yypParser->yyhwm++;
			      assert( yypParser->yyhwm == (int)(yypParser->yytos - yypParser->yystack) );
			        }
#endif
#if YYSTACKDEPTH>0 
	        if( yypParser->yytos>yypParser->yystackEnd ){
			    yypParser->yytos--;
			        yyStackOverflow(yypParser);
				    return;
				      }
#else
		  if( yypParser->yytos>=&yypParser->yystack[yypParser->yystksz] ){
			      if( yyGrowStack(yypParser) ){
				            yypParser->yytos--;
					          yyStackOverflow(yypParser);
						        return;
							    }
			        }
#endif
		    if( yyNewState > YY_MAX_SHIFT ){
			        yyNewState += YY_MIN_REDUCE - YY_MIN_SHIFTREDUCE;
				  }
		      yytos = yypParser->yytos;
		        yytos->stateno = yyNewState;
			  yytos->major = yyMajor;
			    yytos->minor.yy0 = yyMinor;
			      yyTraceShift(yypParser, yyNewState, "Shift");
}

/* For rule J, yyRuleInfoLhs[J] contains the symbol on the left-hand side
 * ** of that rule */
static const YYCODETYPE yyRuleInfoLhs[] = {
	   119,  /* (0) document ::= statement_list */
	       97,  /* (1) statement_list ::= statement */
	           97,  /* (2) statement_list ::= statement_list EOL statement */
		       98,  /* (3) statement ::= */
		           98,  /* (4) statement ::= direction */
			       98,  /* (5) statement ::= lvalue ASSIGN rvalue */
			           98,  /* (6) statement ::= PLACENAME COLON unnamed_statement */
				       98,  /* (7) statement ::= PLACENAME COLON position */
				           98,  /* (8) statement ::= unnamed_statement */
					       98,  /* (9) statement ::= print prlist */
					           98,  /* (10) statement ::= ASSERT LP expr EQ expr RP */
						       98,  /* (11) statement ::= ASSERT LP position EQ position RP */
						           98,  /* (12) statement ::= DEFINE ID CODEBLOCK */
							      114,  /* (13) rvalue ::= PLACENAME */
							         122,  /* (14) pritem ::= FILL */
								    122,  /* (15) pritem ::= COLOR */
								       122,  /* (16) pritem ::= THICKNESS */
								          122,  /* (17) pritem ::= rvalue */
									     122,  /* (18) pritem ::= STRING */
									        123,  /* (19) prsep ::= COMMA */
										    99,  /* (20) unnamed_statement ::= basetype attribute_list */
										       100,  /* (21) basetype ::= CLASSNAME */
										          100,  /* (22) basetype ::= STRING textposition */
											     100,  /* (23) basetype ::= LB savelist statement_list RB */
											        125,  /* (24) savelist ::= */
												   117,  /* (25) relexpr ::= expr */
												      117,  /* (26) relexpr ::= expr PERCENT */
												         118,  /* (27) optrelexpr ::= */
													    124,  /* (28) attribute_list ::= relexpr alist */
													       127,  /* (29) attribute ::= numproperty relexpr */
													          127,  /* (30) attribute ::= dashproperty expr */
														     127,  /* (31) attribute ::= dashproperty */
														        127,  /* (32) attribute ::= colorproperty rvalue */
															   127,  /* (33) attribute ::= go direction optrelexpr */
															      127,  /* (34) attribute ::= go direction even position */
															         127,  /* (35) attribute ::= CLOSE */
																    127,  /* (36) attribute ::= CHOP */
																       127,  /* (37) attribute ::= FROM position */
																          127,  /* (38) attribute ::= TO position */
																	     127,  /* (39) attribute ::= THEN */
																	        127,  /* (40) attribute ::= THEN optrelexpr HEADING expr */
																		   127,  /* (41) attribute ::= THEN optrelexpr EDGEPT */
																		      127,  /* (42) attribute ::= GO optrelexpr HEADING expr */
																		         127,  /* (43) attribute ::= GO optrelexpr EDGEPT */
																			    127,  /* (44) attribute ::= AT position */
																			       127,  /* (45) attribute ::= SAME */
																			          127,  /* (46) attribute ::= SAME AS object */
																				     127,  /* (47) attribute ::= STRING textposition */
																				        127,  /* (48) attribute ::= FIT */
																					   127,  /* (49) attribute ::= BEHIND object */
																					      130,  /* (50) withclause ::= DOT_E edge AT position */
																					         130,  /* (51) withclause ::= edge AT position */
																						    102,  /* (52) numproperty ::= HEIGHT|WIDTH|RADIUS|DIAMETER|THICKNESS */
																						       129,  /* (53) boolproperty ::= CW */
																						          129,  /* (54) boolproperty ::= CCW */
																							     129,  /* (55) boolproperty ::= LARROW */
																							        129,  /* (56) boolproperty ::= RARROW */
																								   129,  /* (57) boolproperty ::= LRARROW */
																								      129,  /* (58) boolproperty ::= INVIS */
																								         129,  /* (59) boolproperty ::= THICK */
																									    129,  /* (60) boolproperty ::= THIN */
																									       113,  /* (61) textposition ::= */
																									          113,  /* (62) textposition ::= textposition CENTER|LJUST|RJUST|ABOVE|BELOW|ITALIC|BOLD|ALIGNED|BIG|SMALL */
																										     108,  /* (63) position ::= expr COMMA expr */
																										        108,  /* (64) position ::= place PLUS expr COMMA expr */
																											   108,  /* (65) position ::= place MINUS expr COMMA expr */
																											      108,  /* (66) position ::= place PLUS LP expr COMMA expr RP */
																											         108,  /* (67) position ::= place MINUS LP expr COMMA expr RP */
																												    108,  /* (68) position ::= LP position COMMA position RP */
																												       108,  /* (69) position ::= LP position RP */
																												          108,  /* (70) position ::= expr between position AND position */
																													     108,  /* (71) position ::= expr LT position COMMA position GT */
																													        108,  /* (72) position ::= expr ABOVE position */
																														   108,  /* (73) position ::= expr BELOW position */
																														      108,  /* (74) position ::= expr LEFT OF position */
																														         108,  /* (75) position ::= expr RIGHT OF position */
																															    108,  /* (76) position ::= expr ON HEADING EDGEPT OF position */
																															       108,  /* (77) position ::= expr HEADING EDGEPT OF position */
																															          108,  /* (78) position ::= expr EDGEPT OF position */
																																     108,  /* (79) position ::= expr ON HEADING expr FROM position */
																																        108,  /* (80) position ::= expr HEADING expr FROM position */
																																	   109,  /* (81) place ::= edge OF object */
																																	      132,  /* (82) place2 ::= object */
																																	         132,  /* (83) place2 ::= object DOT_E edge */
																																		    132,  /* (84) place2 ::= NTH VERTEX OF object */
																																		       110,  /* (85) object ::= nth */
																																		          110,  /* (86) object ::= nth OF|IN object */
																																			     111,  /* (87) objectname ::= PLACENAME */
																																			        111,  /* (88) objectname ::= objectname DOT_U PLACENAME */
																																				   112,  /* (89) nth ::= NTH CLASSNAME */
																																				      112,  /* (90) nth ::= NTH LAST CLASSNAME */
																																				         112,  /* (91) nth ::= LAST CLASSNAME */
																																					    112,  /* (92) nth ::= LAST */
																																					       112,  /* (93) nth ::= NTH LB RB */
																																					          112,  /* (94) nth ::= NTH LAST LB RB */
																																						     112,  /* (95) nth ::= LAST LB RB */
																																						        101,  /* (96) expr ::= expr PLUS expr */
																																							   101,  /* (97) expr ::= expr MINUS expr */
																																							      101,  /* (98) expr ::= expr STAR expr */
																																							         101,  /* (99) expr ::= expr SLASH expr */
																																								    101,  /* (100) expr ::= MINUS expr */
																																								       101,  /* (101) expr ::= PLUS expr */
																																								          101,  /* (102) expr ::= LP expr RP */
																																									     101,  /* (103) expr ::= LP FILL|COLOR|THICKNESS RP */
																																									        101,  /* (104) expr ::= NUMBER */
																																										   101,  /* (105) expr ::= ID */
																																										      101,  /* (106) expr ::= FUNC1 LP expr RP */
																																										         101,  /* (107) expr ::= FUNC2 LP expr COMMA expr RP */
																																											    101,  /* (108) expr ::= DIST LP position COMMA position RP */
																																											       101,  /* (109) expr ::= place2 DOT_XY X */
																																											          101,  /* (110) expr ::= place2 DOT_XY Y */
																																												     101,  /* (111) expr ::= object DOT_L numproperty */
																																												        101,  /* (112) expr ::= object DOT_L dashproperty */
																																													   101,  /* (113) expr ::= object DOT_L colorproperty */
																																													      115,  /* (114) lvalue ::= ID */
																																													         115,  /* (115) lvalue ::= FILL */
																																														    115,  /* (116) lvalue ::= COLOR */
																																														       115,  /* (117) lvalue ::= THICKNESS */
																																														          114,  /* (118) rvalue ::= expr */
																																															     120,  /* (119) print ::= PRINT */
																																															        121,  /* (120) prlist ::= pritem */
																																																   121,  /* (121) prlist ::= prlist prsep pritem */
																																																      104,  /* (122) direction ::= UP */
																																																         104,  /* (123) direction ::= DOWN */
																																																	    104,  /* (124) direction ::= LEFT */
																																																	       104,  /* (125) direction ::= RIGHT */
																																																	          118,  /* (126) optrelexpr ::= relexpr */
																																																		     124,  /* (127) attribute_list ::= alist */
																																																		        126,  /* (128) alist ::= */
																																																			   126,  /* (129) alist ::= alist attribute */
																																																			      127,  /* (130) attribute ::= boolproperty */
																																																			         127,  /* (131) attribute ::= WITH withclause */
																																																				    128,  /* (132) go ::= GO */
																																																				       128,  /* (133) go ::= */
																																																				          116,  /* (134) even ::= UNTIL EVEN WITH */
																																																					     116,  /* (135) even ::= EVEN WITH */
																																																					        105,  /* (136) dashproperty ::= DOTTED */
																																																						   105,  /* (137) dashproperty ::= DASHED */
																																																						      106,  /* (138) colorproperty ::= FILL */
																																																						         106,  /* (139) colorproperty ::= COLOR */
																																																							    108,  /* (140) position ::= place */
																																																							       131,  /* (141) between ::= WAY BETWEEN */
																																																							          131,  /* (142) between ::= BETWEEN */
																																																								     131,  /* (143) between ::= OF THE WAY BETWEEN */
																																																								        109,  /* (144) place ::= place2 */
																																																									   103,  /* (145) edge ::= CENTER */
																																																									      103,  /* (146) edge ::= EDGEPT */
																																																									         103,  /* (147) edge ::= TOP */
																																																										    103,  /* (148) edge ::= BOTTOM */
																																																										       103,  /* (149) edge ::= START */
																																																										          103,  /* (150) edge ::= END */
																																																											     103,  /* (151) edge ::= RIGHT */
																																																											        103,  /* (152) edge ::= LEFT */
																																																												   110,  /* (153) object ::= objectname */
};

/* For rule J, yyRuleInfoNRhs[J] contains the negative of the number
 * ** of symbols on the right-hand side of that rule. */
static const signed char yyRuleInfoNRhs[] = {
	   -1,  /* (0) document ::= statement_list */
	      -1,  /* (1) statement_list ::= statement */
	         -3,  /* (2) statement_list ::= statement_list EOL statement */
		     0,  /* (3) statement ::= */
		        -1,  /* (4) statement ::= direction */
			   -3,  /* (5) statement ::= lvalue ASSIGN rvalue */
			      -3,  /* (6) statement ::= PLACENAME COLON unnamed_statement */
			         -3,  /* (7) statement ::= PLACENAME COLON position */
				    -1,  /* (8) statement ::= unnamed_statement */
				       -2,  /* (9) statement ::= print prlist */
				          -6,  /* (10) statement ::= ASSERT LP expr EQ expr RP */
					     -6,  /* (11) statement ::= ASSERT LP position EQ position RP */
					        -3,  /* (12) statement ::= DEFINE ID CODEBLOCK */
						   -1,  /* (13) rvalue ::= PLACENAME */
						      -1,  /* (14) pritem ::= FILL */
						         -1,  /* (15) pritem ::= COLOR */
							    -1,  /* (16) pritem ::= THICKNESS */
							       -1,  /* (17) pritem ::= rvalue */
							          -1,  /* (18) pritem ::= STRING */
								     -1,  /* (19) prsep ::= COMMA */
								        -2,  /* (20) unnamed_statement ::= basetype attribute_list */
									   -1,  /* (21) basetype ::= CLASSNAME */
									      -2,  /* (22) basetype ::= STRING textposition */
									         -4,  /* (23) basetype ::= LB savelist statement_list RB */
										     0,  /* (24) savelist ::= */
										        -1,  /* (25) relexpr ::= expr */
											   -2,  /* (26) relexpr ::= expr PERCENT */
											       0,  /* (27) optrelexpr ::= */
											          -2,  /* (28) attribute_list ::= relexpr alist */
												     -2,  /* (29) attribute ::= numproperty relexpr */
												        -2,  /* (30) attribute ::= dashproperty expr */
													   -1,  /* (31) attribute ::= dashproperty */
													      -2,  /* (32) attribute ::= colorproperty rvalue */
													         -3,  /* (33) attribute ::= go direction optrelexpr */
														    -4,  /* (34) attribute ::= go direction even position */
														       -1,  /* (35) attribute ::= CLOSE */
														          -1,  /* (36) attribute ::= CHOP */
															     -2,  /* (37) attribute ::= FROM position */
															        -2,  /* (38) attribute ::= TO position */
																   -1,  /* (39) attribute ::= THEN */
																      -4,  /* (40) attribute ::= THEN optrelexpr HEADING expr */
																         -3,  /* (41) attribute ::= THEN optrelexpr EDGEPT */
																	    -4,  /* (42) attribute ::= GO optrelexpr HEADING expr */
																	       -3,  /* (43) attribute ::= GO optrelexpr EDGEPT */
																	          -2,  /* (44) attribute ::= AT position */
																		     -1,  /* (45) attribute ::= SAME */
																		        -3,  /* (46) attribute ::= SAME AS object */
																			   -2,  /* (47) attribute ::= STRING textposition */
																			      -1,  /* (48) attribute ::= FIT */
																			         -2,  /* (49) attribute ::= BEHIND object */
																				    -4,  /* (50) withclause ::= DOT_E edge AT position */
																				       -3,  /* (51) withclause ::= edge AT position */
																				          -1,  /* (52) numproperty ::= HEIGHT|WIDTH|RADIUS|DIAMETER|THICKNESS */
																					     -1,  /* (53) boolproperty ::= CW */
																					        -1,  /* (54) boolproperty ::= CCW */
																						   -1,  /* (55) boolproperty ::= LARROW */
																						      -1,  /* (56) boolproperty ::= RARROW */
																						         -1,  /* (57) boolproperty ::= LRARROW */
																							    -1,  /* (58) boolproperty ::= INVIS */
																							       -1,  /* (59) boolproperty ::= THICK */
																							          -1,  /* (60) boolproperty ::= THIN */
																								      0,  /* (61) textposition ::= */
																								         -2,  /* (62) textposition ::= textposition CENTER|LJUST|RJUST|ABOVE|BELOW|ITALIC|BOLD|ALIGNED|BIG|SMALL */
																									    -3,  /* (63) position ::= expr COMMA expr */
																									       -5,  /* (64) position ::= place PLUS expr COMMA expr */
																									          -5,  /* (65) position ::= place MINUS expr COMMA expr */
																										     -7,  /* (66) position ::= place PLUS LP expr COMMA expr RP */
																										        -7,  /* (67) position ::= place MINUS LP expr COMMA expr RP */
																											   -5,  /* (68) position ::= LP position COMMA position RP */
																											      -3,  /* (69) position ::= LP position RP */
																											         -5,  /* (70) position ::= expr between position AND position */
																												    -6,  /* (71) position ::= expr LT position COMMA position GT */
																												       -3,  /* (72) position ::= expr ABOVE position */
																												          -3,  /* (73) position ::= expr BELOW position */
																													     -4,  /* (74) position ::= expr LEFT OF position */
																													        -4,  /* (75) position ::= expr RIGHT OF position */
																														   -6,  /* (76) position ::= expr ON HEADING EDGEPT OF position */
																														      -5,  /* (77) position ::= expr HEADING EDGEPT OF position */
																														         -4,  /* (78) position ::= expr EDGEPT OF position */
																															    -6,  /* (79) position ::= expr ON HEADING expr FROM position */
																															       -5,  /* (80) position ::= expr HEADING expr FROM position */
																															          -3,  /* (81) place ::= edge OF object */
																																     -1,  /* (82) place2 ::= object */
																																        -3,  /* (83) place2 ::= object DOT_E edge */
																																	   -4,  /* (84) place2 ::= NTH VERTEX OF object */
																																	      -1,  /* (85) object ::= nth */
																																	         -3,  /* (86) object ::= nth OF|IN object */
																																		    -1,  /* (87) objectname ::= PLACENAME */
																																		       -3,  /* (88) objectname ::= objectname DOT_U PLACENAME */
																																		          -2,  /* (89) nth ::= NTH CLASSNAME */
																																			     -3,  /* (90) nth ::= NTH LAST CLASSNAME */
																																			        -2,  /* (91) nth ::= LAST CLASSNAME */
																																				   -1,  /* (92) nth ::= LAST */
																																				      -3,  /* (93) nth ::= NTH LB RB */
																																				         -4,  /* (94) nth ::= NTH LAST LB RB */
																																					    -3,  /* (95) nth ::= LAST LB RB */
																																					       -3,  /* (96) expr ::= expr PLUS expr */
																																					          -3,  /* (97) expr ::= expr MINUS expr */
																																						     -3,  /* (98) expr ::= expr STAR expr */
																																						        -3,  /* (99) expr ::= expr SLASH expr */
																																							   -2,  /* (100) expr ::= MINUS expr */
																																							      -2,  /* (101) expr ::= PLUS expr */
																																							         -3,  /* (102) expr ::= LP expr RP */
																																								    -3,  /* (103) expr ::= LP FILL|COLOR|THICKNESS RP */
																																								       -1,  /* (104) expr ::= NUMBER */
																																								          -1,  /* (105) expr ::= ID */
																																									     -4,  /* (106) expr ::= FUNC1 LP expr RP */
																																									        -6,  /* (107) expr ::= FUNC2 LP expr COMMA expr RP */
																																										   -6,  /* (108) expr ::= DIST LP position COMMA position RP */
																																										      -3,  /* (109) expr ::= place2 DOT_XY X */
																																										         -3,  /* (110) expr ::= place2 DOT_XY Y */
																																											    -3,  /* (111) expr ::= object DOT_L numproperty */
																																											       -3,  /* (112) expr ::= object DOT_L dashproperty */
																																											          -3,  /* (113) expr ::= object DOT_L colorproperty */
																																												     -1,  /* (114) lvalue ::= ID */
																																												        -1,  /* (115) lvalue ::= FILL */
																																													   -1,  /* (116) lvalue ::= COLOR */
																																													      -1,  /* (117) lvalue ::= THICKNESS */
																																													         -1,  /* (118) rvalue ::= expr */
																																														    -1,  /* (119) print ::= PRINT */
																																														       -1,  /* (120) prlist ::= pritem */
																																														          -3,  /* (121) prlist ::= prlist prsep pritem */
																																															     -1,  /* (122) direction ::= UP */
																																															        -1,  /* (123) direction ::= DOWN */
																																																   -1,  /* (124) direction ::= LEFT */
																																																      -1,  /* (125) direction ::= RIGHT */
																																																         -1,  /* (126) optrelexpr ::= relexpr */
																																																	    -1,  /* (127) attribute_list ::= alist */
																																																	        0,  /* (128) alist ::= */
																																																		   -2,  /* (129) alist ::= alist attribute */
																																																		      -1,  /* (130) attribute ::= boolproperty */
																																																		         -2,  /* (131) attribute ::= WITH withclause */
																																																			    -1,  /* (132) go ::= GO */
																																																			        0,  /* (133) go ::= */
																																																				   -3,  /* (134) even ::= UNTIL EVEN WITH */
																																																				      -2,  /* (135) even ::= EVEN WITH */
																																																				         -1,  /* (136) dashproperty ::= DOTTED */
																																																					    -1,  /* (137) dashproperty ::= DASHED */
																																																					       -1,  /* (138) colorproperty ::= FILL */
																																																					          -1,  /* (139) colorproperty ::= COLOR */
																																																						     -1,  /* (140) position ::= place */
																																																						        -2,  /* (141) between ::= WAY BETWEEN */
																																																							   -1,  /* (142) between ::= BETWEEN */
																																																							      -4,  /* (143) between ::= OF THE WAY BETWEEN */
																																																							         -1,  /* (144) place ::= place2 */
																																																								    -1,  /* (145) edge ::= CENTER */
																																																								       -1,  /* (146) edge ::= EDGEPT */
																																																								          -1,  /* (147) edge ::= TOP */
																																																									     -1,  /* (148) edge ::= BOTTOM */
																																																									        -1,  /* (149) edge ::= START */
																																																										   -1,  /* (150) edge ::= END */
																																																										      -1,  /* (151) edge ::= RIGHT */
																																																										         -1,  /* (152) edge ::= LEFT */
																																																											    -1,  /* (153) object ::= objectname */
};

static void yy_accept(yyParser*);  /* Forward Declaration */

/*
 * ** Perform a reduce action and the shift that must immediately
 * ** follow the reduce.
 * **
 * ** The yyLookahead and yyLookaheadToken parameters provide reduce actions
 * ** access to the lookahead token (if any).  The yyLookahead will be YYNOCODE
 * ** if the lookahead token has already been consumed.  As this procedure is
 * ** only called from one place, optimizing compilers will in-line it, which
 * ** means that the extra parameters have no performance impact.
 * */
static YYACTIONTYPE yy_reduce(
		  yyParser *yypParser,         /* The parser */
		    unsigned int yyruleno,       /* Number of the rule by which to reduce */
		      int yyLookahead,             /* Lookahead token, or YYNOCODE if none */
		        pik_parserTOKENTYPE yyLookaheadToken  /* Value of the lookahead token */
			  pik_parserCTX_PDECL                   /* %extra_context */
		){
	  int yygoto;                     /* The next state */
	    YYACTIONTYPE yyact;             /* The next action */
	      yyStackEntry *yymsp;            /* The top of the parser's stack */
	        int yysize;                     /* Amount to pop the stack */
		  pik_parserARG_FETCH
			    (void)yyLookahead;
		    (void)yyLookaheadToken;
		      yymsp = yypParser->yytos;
		        assert( yyruleno<(int)(sizeof(yyRuleName)/sizeof(yyRuleName[0])) );
#ifndef NDEBUG
			  if( yyTraceFILE ){
				      yysize = yyRuleInfoNRhs[yyruleno];
				          if( yysize ){
						        fprintf(yyTraceFILE, "%sReduce %d [%s]%s, pop back to state %d.\n",
									        yyTracePrompt,
										        yyruleno, yyRuleName[yyruleno],
											        yyruleno<YYNRULE_WITH_ACTION ? "" : " without external action",
												        yymsp[yysize].stateno);
							    }else{
								          fprintf(yyTraceFILE, "%sReduce %d [%s]%s.\n",
											          yyTracePrompt, yyruleno, yyRuleName[yyruleno],
												          yyruleno<YYNRULE_WITH_ACTION ? "" : " without external action");
									      }
					    }
#endif /* NDEBUG */

			    /* Check that the stack is large enough to grow by a single entry
			     *   ** if the RHS of the rule is empty.  This ensures that there is room
			     *     ** enough on the stack to push the LHS value */
			    if( yyRuleInfoNRhs[yyruleno]==0 ){
#ifdef YYTRACKMAXSTACKDEPTH
				        if( (int)(yypParser->yytos - yypParser->yystack)>yypParser->yyhwm ){
						      yypParser->yyhwm++;
						            assert( yypParser->yyhwm == (int)(yypParser->yytos - yypParser->yystack));
							        }
#endif
#if YYSTACKDEPTH>0 
					    if( yypParser->yytos>=yypParser->yystackEnd ){
						          yyStackOverflow(yypParser);
							        /* The call to yyStackOverflow() above pops the stack until it is
								 *       ** empty, causing the main parser loop to exit.  So the return value
								 *             ** is never used and does not matter. */
							        return 0;
								    }
#else
					        if( yypParser->yytos>=&yypParser->yystack[yypParser->yystksz-1] ){
							      if( yyGrowStack(yypParser) ){
								              yyStackOverflow(yypParser);
									              /* The call to yyStackOverflow() above pops the stack until it is
										       *         ** empty, causing the main parser loop to exit.  So the return value
										       *                 ** is never used and does not matter. */
									              return 0;
										            }
							            yymsp = yypParser->yytos;
								        }
#endif
						  }

			      switch( yyruleno ){
				        /* Beginning here are the reduction cases.  A typical example
					 *   ** follows:
					 *     **   case 0:
					 *       **  #line <lineno> <grammarfile>
					 *         **     { ... }           // User supplied code
					 *           **  #line <lineno> <thisfile>
					 *             **     break;
					 *               */
				      /********** Begin reduce actions **********************************************/
				              YYMINORTYPE yylhsminor;
					            case 0: /* document ::= statement_list */
#line 521 "pikchr.y"
					      {pik_render(p,yymsp[0].minor.yy191);}
#line 2407 "pikchr.c"
					              break;
						            case 1: /* statement_list ::= statement */
#line 524 "pikchr.y"
						      { yylhsminor.yy191 = pik_elist_append(p,0,yymsp[0].minor.yy138); }
#line 2412 "pikchr.c"
						        yymsp[0].minor.yy191 = yylhsminor.yy191;
							        break;
								      case 2: /* statement_list ::= statement_list EOL statement */
#line 526 "pikchr.y"
								{ yylhsminor.yy191 = pik_elist_append(p,yymsp[-2].minor.yy191,yymsp[0].minor.yy138); }
#line 2418 "pikchr.c"
								  yymsp[-2].minor.yy191 = yylhsminor.yy191;
								          break;
									        case 3: /* statement ::= */
#line 529 "pikchr.y"
									  { yymsp[1].minor.yy138 = 0; }
#line 2424 "pikchr.c"
									          break;
										        case 4: /* statement ::= direction */
#line 530 "pikchr.y"
										  { pik_set_direction(p,yymsp[0].minor.yy0.eCode);  yylhsminor.yy138=0; }
#line 2429 "pikchr.c"
										    yymsp[0].minor.yy138 = yylhsminor.yy138;
										            break;
											          case 5: /* statement ::= lvalue ASSIGN rvalue */
#line 531 "pikchr.y"
											    {pik_set_var(p,&yymsp[-2].minor.yy0,yymsp[0].minor.yy121,&yymsp[-1].minor.yy0); yylhsminor.yy138=0;}
#line 2435 "pikchr.c"
											      yymsp[-2].minor.yy138 = yylhsminor.yy138;
											              break;
												            case 6: /* statement ::= PLACENAME COLON unnamed_statement */
#line 533 "pikchr.y"
												      { yylhsminor.yy138 = yymsp[0].minor.yy138;  pik_elem_setname(p,yymsp[0].minor.yy138,&yymsp[-2].minor.yy0); }
#line 2441 "pikchr.c"
												        yymsp[-2].minor.yy138 = yylhsminor.yy138;
													        break;
														      case 7: /* statement ::= PLACENAME COLON position */
#line 535 "pikchr.y"
														{ yylhsminor.yy138 = pik_elem_new(p,0,0,0);
															                 if(yylhsminor.yy138){ yylhsminor.yy138->ptAt = yymsp[0].minor.yy47; pik_elem_setname(p,yylhsminor.yy138,&yymsp[-2].minor.yy0); }}
#line 2448 "pikchr.c"
														  yymsp[-2].minor.yy138 = yylhsminor.yy138;
														          break;
															        case 8: /* statement ::= unnamed_statement */
#line 537 "pikchr.y"
															  {yylhsminor.yy138 = yymsp[0].minor.yy138;}
#line 2454 "pikchr.c"
															    yymsp[0].minor.yy138 = yylhsminor.yy138;
															            break;
																          case 9: /* statement ::= print prlist */
#line 538 "pikchr.y"
																    {pik_append(p,"<br>\n",5); yymsp[-1].minor.yy138=0;}
#line 2460 "pikchr.c"
																            break;
																	          case 10: /* statement ::= ASSERT LP expr EQ expr RP */
#line 543 "pikchr.y"
																	    {yymsp[-5].minor.yy138=pik_assert(p,yymsp[-3].minor.yy121,&yymsp[-2].minor.yy0,yymsp[-1].minor.yy121);}
#line 2465 "pikchr.c"
																	            break;
																		          case 11: /* statement ::= ASSERT LP position EQ position RP */
#line 545 "pikchr.y"
																		    {yymsp[-5].minor.yy138=pik_position_assert(p,&yymsp[-3].minor.yy47,&yymsp[-2].minor.yy0,&yymsp[-1].minor.yy47);}
#line 2470 "pikchr.c"
																		            break;
																			          case 12: /* statement ::= DEFINE ID CODEBLOCK */
#line 546 "pikchr.y"
																			    {yymsp[-2].minor.yy138=0; pik_add_macro(p,&yymsp[-1].minor.yy0,&yymsp[0].minor.yy0);}
#line 2475 "pikchr.c"
																			            break;
																				          case 13: /* rvalue ::= PLACENAME */
#line 557 "pikchr.y"
																				    {yylhsminor.yy121 = pik_lookup_color(p,&yymsp[0].minor.yy0);}
#line 2480 "pikchr.c"
																				      yymsp[0].minor.yy121 = yylhsminor.yy121;
																				              break;
																					            case 14: /* pritem ::= FILL */
																					            case 15: /* pritem ::= COLOR */ yytestcase(yyruleno==15);
																										          case 16: /* pritem ::= THICKNESS */ yytestcase(yyruleno==16);
#line 562 "pikchr.y"
																															      {pik_append_num(p,"",pik_value(p,yymsp[0].minor.yy0.z,yymsp[0].minor.yy0.n,0));}
#line 2488 "pikchr.c"
																															              break;
																																            case 17: /* pritem ::= rvalue */
#line 565 "pikchr.y"
																																      {pik_append_num(p,"",yymsp[0].minor.yy121);}
#line 2493 "pikchr.c"
																																              break;
																																	            case 18: /* pritem ::= STRING */
#line 566 "pikchr.y"
																																	      {pik_append_text(p,yymsp[0].minor.yy0.z+1,yymsp[0].minor.yy0.n-2,0);}
#line 2498 "pikchr.c"
																																	              break;
																																		            case 19: /* prsep ::= COMMA */
#line 567 "pikchr.y"
																																		      {pik_append(p, " ", 1);}
#line 2503 "pikchr.c"
																																		              break;
																																			            case 20: /* unnamed_statement ::= basetype attribute_list */
#line 570 "pikchr.y"
																																			      {yylhsminor.yy138 = yymsp[-1].minor.yy138; pik_after_adding_attributes(p,yylhsminor.yy138);}
#line 2508 "pikchr.c"
																																			        yymsp[-1].minor.yy138 = yylhsminor.yy138;
																																				        break;
																																					      case 21: /* basetype ::= CLASSNAME */
#line 572 "pikchr.y"
																																					{yylhsminor.yy138 = pik_elem_new(p,&yymsp[0].minor.yy0,0,0); }
#line 2514 "pikchr.c"
																																					  yymsp[0].minor.yy138 = yylhsminor.yy138;
																																					          break;
																																						        case 22: /* basetype ::= STRING textposition */
#line 574 "pikchr.y"
																																						  {yymsp[-1].minor.yy0.eCode = yymsp[0].minor.yy46; yylhsminor.yy138 = pik_elem_new(p,0,&yymsp[-1].minor.yy0,0); }
#line 2520 "pikchr.c"
																																						    yymsp[-1].minor.yy138 = yylhsminor.yy138;
																																						            break;
																																							          case 23: /* basetype ::= LB savelist statement_list RB */
#line 576 "pikchr.y"
																																							    { p->list = yymsp[-2].minor.yy191; yymsp[-3].minor.yy138 = pik_elem_new(p,0,0,yymsp[-1].minor.yy191); if(yymsp[-3].minor.yy138) yymsp[-3].minor.yy138->errTok = yymsp[0].minor.yy0; }
#line 2526 "pikchr.c"
																																							            break;
																																								          case 24: /* savelist ::= */
#line 581 "pikchr.y"
																																								    {yymsp[1].minor.yy191 = p->list; p->list = 0;}
#line 2531 "pikchr.c"
																																								            break;
																																									          case 25: /* relexpr ::= expr */
#line 588 "pikchr.y"
																																									    {yylhsminor.yy134.rAbs = yymsp[0].minor.yy121; yylhsminor.yy134.rRel = 0;}
#line 2536 "pikchr.c"
																																									      yymsp[0].minor.yy134 = yylhsminor.yy134;
																																									              break;
																																										            case 26: /* relexpr ::= expr PERCENT */
#line 589 "pikchr.y"
																																										      {yylhsminor.yy134.rAbs = 0; yylhsminor.yy134.rRel = yymsp[-1].minor.yy121/100;}
#line 2542 "pikchr.c"
																																										        yymsp[-1].minor.yy134 = yylhsminor.yy134;
																																											        break;
																																												      case 27: /* optrelexpr ::= */
#line 591 "pikchr.y"
																																												{yymsp[1].minor.yy134.rAbs = 0; yymsp[1].minor.yy134.rRel = 1.0;}
#line 2548 "pikchr.c"
																																												        break;
																																													      case 28: /* attribute_list ::= relexpr alist */
#line 593 "pikchr.y"
																																													{pik_add_direction(p,0,&yymsp[-1].minor.yy134);}
#line 2553 "pikchr.c"
																																													        break;
																																														      case 29: /* attribute ::= numproperty relexpr */
#line 597 "pikchr.y"
																																														{ pik_set_numprop(p,&yymsp[-1].minor.yy0,&yymsp[0].minor.yy134); }
#line 2558 "pikchr.c"
																																														        break;
																																															      case 30: /* attribute ::= dashproperty expr */
#line 598 "pikchr.y"
																																															{ pik_set_dashed(p,&yymsp[-1].minor.yy0,&yymsp[0].minor.yy121); }
#line 2563 "pikchr.c"
																																															        break;
																																																      case 31: /* attribute ::= dashproperty */
#line 599 "pikchr.y"
																																																{ pik_set_dashed(p,&yymsp[0].minor.yy0,0);  }
#line 2568 "pikchr.c"
																																																        break;
																																																	      case 32: /* attribute ::= colorproperty rvalue */
#line 600 "pikchr.y"
																																																	{ pik_set_clrprop(p,&yymsp[-1].minor.yy0,yymsp[0].minor.yy121); }
#line 2573 "pikchr.c"
																																																	        break;
																																																		      case 33: /* attribute ::= go direction optrelexpr */
#line 601 "pikchr.y"
																																																		{ pik_add_direction(p,&yymsp[-1].minor.yy0,&yymsp[0].minor.yy134);}
#line 2578 "pikchr.c"
																																																		        break;
																																																			      case 34: /* attribute ::= go direction even position */
#line 602 "pikchr.y"
																																																			{pik_evenwith(p,&yymsp[-2].minor.yy0,&yymsp[0].minor.yy47);}
#line 2583 "pikchr.c"
																																																			        break;
																																																				      case 35: /* attribute ::= CLOSE */
#line 603 "pikchr.y"
																																																				{ pik_close_path(p,&yymsp[0].minor.yy0); }
#line 2588 "pikchr.c"
																																																				        break;
																																																					      case 36: /* attribute ::= CHOP */
#line 604 "pikchr.y"
																																																					{ p->cur->bChop = 1; }
#line 2593 "pikchr.c"
																																																					        break;
																																																						      case 37: /* attribute ::= FROM position */
#line 605 "pikchr.y"
																																																						{ pik_set_from(p,p->cur,&yymsp[-1].minor.yy0,&yymsp[0].minor.yy47); }
#line 2598 "pikchr.c"
																																																						        break;
																																																							      case 38: /* attribute ::= TO position */
#line 606 "pikchr.y"
																																																							{ pik_add_to(p,p->cur,&yymsp[-1].minor.yy0,&yymsp[0].minor.yy47); }
#line 2603 "pikchr.c"
																																																							        break;
																																																								      case 39: /* attribute ::= THEN */
#line 607 "pikchr.y"
																																																								{ pik_then(p, &yymsp[0].minor.yy0, p->cur); }
#line 2608 "pikchr.c"
																																																								        break;
																																																									      case 40: /* attribute ::= THEN optrelexpr HEADING expr */
																																																									      case 42: /* attribute ::= GO optrelexpr HEADING expr */ yytestcase(yyruleno==42);
#line 609 "pikchr.y"
																																																																      {pik_move_hdg(p,&yymsp[-2].minor.yy134,&yymsp[-1].minor.yy0,yymsp[0].minor.yy121,0,&yymsp[-3].minor.yy0);}
#line 2614 "pikchr.c"
																																																																              break;
																																																																	            case 41: /* attribute ::= THEN optrelexpr EDGEPT */
																																																																	            case 43: /* attribute ::= GO optrelexpr EDGEPT */ yytestcase(yyruleno==43);
#line 610 "pikchr.y"
																																																																								      {pik_move_hdg(p,&yymsp[-1].minor.yy134,0,0,&yymsp[0].minor.yy0,&yymsp[-2].minor.yy0);}
#line 2620 "pikchr.c"
																																																																								              break;
																																																																									            case 44: /* attribute ::= AT position */
#line 615 "pikchr.y"
																																																																									      { pik_set_at(p,0,&yymsp[0].minor.yy47,&yymsp[-1].minor.yy0); }
#line 2625 "pikchr.c"
																																																																									              break;
																																																																										            case 45: /* attribute ::= SAME */
#line 617 "pikchr.y"
																																																																										      {pik_same(p,0,&yymsp[0].minor.yy0);}
#line 2630 "pikchr.c"
																																																																										              break;
																																																																											            case 46: /* attribute ::= SAME AS object */
#line 618 "pikchr.y"
																																																																											      {pik_same(p,yymsp[0].minor.yy138,&yymsp[-2].minor.yy0);}
#line 2635 "pikchr.c"
																																																																											              break;
																																																																												            case 47: /* attribute ::= STRING textposition */
#line 619 "pikchr.y"
																																																																												      {pik_add_txt(p,&yymsp[-1].minor.yy0,yymsp[0].minor.yy46);}
#line 2640 "pikchr.c"
																																																																												              break;
																																																																													            case 48: /* attribute ::= FIT */
#line 620 "pikchr.y"
																																																																													      {pik_size_to_fit(p,&yymsp[0].minor.yy0,3); }
#line 2645 "pikchr.c"
																																																																													              break;
																																																																														            case 49: /* attribute ::= BEHIND object */
#line 621 "pikchr.y"
																																																																														      {pik_behind(p,yymsp[0].minor.yy138);}
#line 2650 "pikchr.c"
																																																																														              break;
																																																																															            case 50: /* withclause ::= DOT_E edge AT position */
																																																																															            case 51: /* withclause ::= edge AT position */ yytestcase(yyruleno==51);
#line 629 "pikchr.y"
																																																																																						   { pik_set_at(p,&yymsp[-2].minor.yy0,&yymsp[0].minor.yy47,&yymsp[-1].minor.yy0); }
#line 2656 "pikchr.c"
																																																																																						           break;
																																																																																							         case 52: /* numproperty ::= HEIGHT|WIDTH|RADIUS|DIAMETER|THICKNESS */
#line 633 "pikchr.y"
																																																																																							   {yylhsminor.yy0 = yymsp[0].minor.yy0;}
#line 2661 "pikchr.c"
																																																																																							     yymsp[0].minor.yy0 = yylhsminor.yy0;
																																																																																							             break;
																																																																																								           case 53: /* boolproperty ::= CW */
#line 644 "pikchr.y"
																																																																																								     {p->cur->cw = 1;}
#line 2667 "pikchr.c"
																																																																																								             break;
																																																																																									           case 54: /* boolproperty ::= CCW */
#line 645 "pikchr.y"
																																																																																									     {p->cur->cw = 0;}
#line 2672 "pikchr.c"
																																																																																									             break;
																																																																																										           case 55: /* boolproperty ::= LARROW */
#line 646 "pikchr.y"
																																																																																										     {p->cur->larrow=1; p->cur->rarrow=0; }
#line 2677 "pikchr.c"
																																																																																										             break;
																																																																																											           case 56: /* boolproperty ::= RARROW */
#line 647 "pikchr.y"
																																																																																											     {p->cur->larrow=0; p->cur->rarrow=1; }
#line 2682 "pikchr.c"
																																																																																											             break;
																																																																																												           case 57: /* boolproperty ::= LRARROW */
#line 648 "pikchr.y"
																																																																																												     {p->cur->larrow=1; p->cur->rarrow=1; }
#line 2687 "pikchr.c"
																																																																																												             break;
																																																																																													           case 58: /* boolproperty ::= INVIS */
#line 649 "pikchr.y"
																																																																																													     {p->cur->sw = 0.0;}
#line 2692 "pikchr.c"
																																																																																													             break;
																																																																																														           case 59: /* boolproperty ::= THICK */
#line 650 "pikchr.y"
																																																																																														     {p->cur->sw *= 1.5;}
#line 2697 "pikchr.c"
																																																																																														             break;
																																																																																															           case 60: /* boolproperty ::= THIN */
#line 651 "pikchr.y"
																																																																																															     {p->cur->sw *= 0.67;}
#line 2702 "pikchr.c"
																																																																																															             break;
																																																																																																           case 61: /* textposition ::= */
#line 653 "pikchr.y"
																																																																																																     {yymsp[1].minor.yy46 = 0;}
#line 2707 "pikchr.c"
																																																																																																             break;
																																																																																																	           case 62: /* textposition ::= textposition CENTER|LJUST|RJUST|ABOVE|BELOW|ITALIC|BOLD|ALIGNED|BIG|SMALL */
#line 656 "pikchr.y"
																																																																																																	     {yylhsminor.yy46 = pik_text_position(yymsp[-1].minor.yy46,&yymsp[0].minor.yy0);}
#line 2712 "pikchr.c"
																																																																																																	       yymsp[-1].minor.yy46 = yylhsminor.yy46;
																																																																																																	               break;
																																																																																																		             case 63: /* position ::= expr COMMA expr */
#line 659 "pikchr.y"
																																																																																																		       {yylhsminor.yy47.x=yymsp[-2].minor.yy121; yylhsminor.yy47.y=yymsp[0].minor.yy121;}
#line 2718 "pikchr.c"
																																																																																																		         yymsp[-2].minor.yy47 = yylhsminor.yy47;
																																																																																																			         break;
																																																																																																				       case 64: /* position ::= place PLUS expr COMMA expr */
#line 661 "pikchr.y"
																																																																																																				 {yylhsminor.yy47.x=yymsp[-4].minor.yy47.x+yymsp[-2].minor.yy121; yylhsminor.yy47.y=yymsp[-4].minor.yy47.y+yymsp[0].minor.yy121;}
#line 2724 "pikchr.c"
																																																																																																				   yymsp[-4].minor.yy47 = yylhsminor.yy47;
																																																																																																				           break;
																																																																																																					         case 65: /* position ::= place MINUS expr COMMA expr */
#line 662 "pikchr.y"
																																																																																																					   {yylhsminor.yy47.x=yymsp[-4].minor.yy47.x-yymsp[-2].minor.yy121; yylhsminor.yy47.y=yymsp[-4].minor.yy47.y-yymsp[0].minor.yy121;}
#line 2730 "pikchr.c"
																																																																																																					     yymsp[-4].minor.yy47 = yylhsminor.yy47;
																																																																																																					             break;
																																																																																																						           case 66: /* position ::= place PLUS LP expr COMMA expr RP */
#line 664 "pikchr.y"
																																																																																																						     {yylhsminor.yy47.x=yymsp[-6].minor.yy47.x+yymsp[-3].minor.yy121; yylhsminor.yy47.y=yymsp[-6].minor.yy47.y+yymsp[-1].minor.yy121;}
#line 2736 "pikchr.c"
																																																																																																						       yymsp[-6].minor.yy47 = yylhsminor.yy47;
																																																																																																						               break;
																																																																																																							             case 67: /* position ::= place MINUS LP expr COMMA expr RP */
#line 666 "pikchr.y"
																																																																																																							       {yylhsminor.yy47.x=yymsp[-6].minor.yy47.x-yymsp[-3].minor.yy121; yylhsminor.yy47.y=yymsp[-6].minor.yy47.y-yymsp[-1].minor.yy121;}
#line 2742 "pikchr.c"
																																																																																																							         yymsp[-6].minor.yy47 = yylhsminor.yy47;
																																																																																																								         break;
																																																																																																									       case 68: /* position ::= LP position COMMA position RP */
#line 667 "pikchr.y"
																																																																																																									 {yymsp[-4].minor.yy47.x=yymsp[-3].minor.yy47.x; yymsp[-4].minor.yy47.y=yymsp[-1].minor.yy47.y;}
#line 2748 "pikchr.c"
																																																																																																									         break;
																																																																																																										       case 69: /* position ::= LP position RP */
#line 668 "pikchr.y"
																																																																																																										 {yymsp[-2].minor.yy47=yymsp[-1].minor.yy47;}
#line 2753 "pikchr.c"
																																																																																																										         break;
																																																																																																											       case 70: /* position ::= expr between position AND position */
#line 670 "pikchr.y"
																																																																																																											 {yylhsminor.yy47 = pik_position_between(yymsp[-4].minor.yy121,yymsp[-2].minor.yy47,yymsp[0].minor.yy47);}
#line 2758 "pikchr.c"
																																																																																																											   yymsp[-4].minor.yy47 = yylhsminor.yy47;
																																																																																																											           break;
																																																																																																												         case 71: /* position ::= expr LT position COMMA position GT */
#line 672 "pikchr.y"
																																																																																																												   {yylhsminor.yy47 = pik_position_between(yymsp[-5].minor.yy121,yymsp[-3].minor.yy47,yymsp[-1].minor.yy47);}
#line 2764 "pikchr.c"
																																																																																																												     yymsp[-5].minor.yy47 = yylhsminor.yy47;
																																																																																																												             break;
																																																																																																													           case 72: /* position ::= expr ABOVE position */
#line 673 "pikchr.y"
																																																																																																													     {yylhsminor.yy47=yymsp[0].minor.yy47; yylhsminor.yy47.y += yymsp[-2].minor.yy121;}
#line 2770 "pikchr.c"
																																																																																																													       yymsp[-2].minor.yy47 = yylhsminor.yy47;
																																																																																																													               break;
																																																																																																														             case 73: /* position ::= expr BELOW position */
#line 674 "pikchr.y"
																																																																																																														       {yylhsminor.yy47=yymsp[0].minor.yy47; yylhsminor.yy47.y -= yymsp[-2].minor.yy121;}
#line 2776 "pikchr.c"
																																																																																																														         yymsp[-2].minor.yy47 = yylhsminor.yy47;
																																																																																																															         break;
																																																																																																																       case 74: /* position ::= expr LEFT OF position */
#line 675 "pikchr.y"
																																																																																																																 {yylhsminor.yy47=yymsp[0].minor.yy47; yylhsminor.yy47.x -= yymsp[-3].minor.yy121;}
#line 2782 "pikchr.c"
																																																																																																																   yymsp[-3].minor.yy47 = yylhsminor.yy47;
																																																																																																																           break;
																																																																																																																	         case 75: /* position ::= expr RIGHT OF position */
#line 676 "pikchr.y"
																																																																																																																	   {yylhsminor.yy47=yymsp[0].minor.yy47; yylhsminor.yy47.x += yymsp[-3].minor.yy121;}
#line 2788 "pikchr.c"
																																																																																																																	     yymsp[-3].minor.yy47 = yylhsminor.yy47;
																																																																																																																	             break;
																																																																																																																		           case 76: /* position ::= expr ON HEADING EDGEPT OF position */
#line 678 "pikchr.y"
																																																																																																																		     {yylhsminor.yy47 = pik_position_at_hdg(yymsp[-5].minor.yy121,&yymsp[-2].minor.yy0,yymsp[0].minor.yy47);}
#line 2794 "pikchr.c"
																																																																																																																		       yymsp[-5].minor.yy47 = yylhsminor.yy47;
																																																																																																																		               break;
																																																																																																																			             case 77: /* position ::= expr HEADING EDGEPT OF position */
#line 680 "pikchr.y"
																																																																																																																			       {yylhsminor.yy47 = pik_position_at_hdg(yymsp[-4].minor.yy121,&yymsp[-2].minor.yy0,yymsp[0].minor.yy47);}
#line 2800 "pikchr.c"
																																																																																																																			         yymsp[-4].minor.yy47 = yylhsminor.yy47;
																																																																																																																				         break;
																																																																																																																					       case 78: /* position ::= expr EDGEPT OF position */
#line 682 "pikchr.y"
																																																																																																																					 {yylhsminor.yy47 = pik_position_at_hdg(yymsp[-3].minor.yy121,&yymsp[-2].minor.yy0,yymsp[0].minor.yy47);}
#line 2806 "pikchr.c"
																																																																																																																					   yymsp[-3].minor.yy47 = yylhsminor.yy47;
																																																																																																																					           break;
																																																																																																																						         case 79: /* position ::= expr ON HEADING expr FROM position */
#line 684 "pikchr.y"
																																																																																																																						   {yylhsminor.yy47 = pik_position_at_angle(yymsp[-5].minor.yy121,yymsp[-2].minor.yy121,yymsp[0].minor.yy47);}
#line 2812 "pikchr.c"
																																																																																																																						     yymsp[-5].minor.yy47 = yylhsminor.yy47;
																																																																																																																						             break;
																																																																																																																							           case 80: /* position ::= expr HEADING expr FROM position */
#line 686 "pikchr.y"
																																																																																																																							     {yylhsminor.yy47 = pik_position_at_angle(yymsp[-4].minor.yy121,yymsp[-2].minor.yy121,yymsp[0].minor.yy47);}
#line 2818 "pikchr.c"
																																																																																																																							       yymsp[-4].minor.yy47 = yylhsminor.yy47;
																																																																																																																							               break;
																																																																																																																								             case 81: /* place ::= edge OF object */
#line 698 "pikchr.y"
																																																																																																																								       {yylhsminor.yy47 = pik_place_of_elem(p,yymsp[0].minor.yy138,&yymsp[-2].minor.yy0);}
#line 2824 "pikchr.c"
																																																																																																																								         yymsp[-2].minor.yy47 = yylhsminor.yy47;
																																																																																																																									         break;
																																																																																																																										       case 82: /* place2 ::= object */
#line 699 "pikchr.y"
																																																																																																																										 {yylhsminor.yy47 = pik_place_of_elem(p,yymsp[0].minor.yy138,0);}
#line 2830 "pikchr.c"
																																																																																																																										   yymsp[0].minor.yy47 = yylhsminor.yy47;
																																																																																																																										           break;
																																																																																																																											         case 83: /* place2 ::= object DOT_E edge */
#line 700 "pikchr.y"
																																																																																																																											   {yylhsminor.yy47 = pik_place_of_elem(p,yymsp[-2].minor.yy138,&yymsp[0].minor.yy0);}
#line 2836 "pikchr.c"
																																																																																																																											     yymsp[-2].minor.yy47 = yylhsminor.yy47;
																																																																																																																											             break;
																																																																																																																												           case 84: /* place2 ::= NTH VERTEX OF object */
#line 701 "pikchr.y"
																																																																																																																												     {yylhsminor.yy47 = pik_nth_vertex(p,&yymsp[-3].minor.yy0,&yymsp[-2].minor.yy0,yymsp[0].minor.yy138);}
#line 2842 "pikchr.c"
																																																																																																																												       yymsp[-3].minor.yy47 = yylhsminor.yy47;
																																																																																																																												               break;
																																																																																																																													             case 85: /* object ::= nth */
#line 713 "pikchr.y"
																																																																																																																													       {yylhsminor.yy138 = pik_find_nth(p,0,&yymsp[0].minor.yy0);}
#line 2848 "pikchr.c"
																																																																																																																													         yymsp[0].minor.yy138 = yylhsminor.yy138;
																																																																																																																														         break;
																																																																																																																															       case 86: /* object ::= nth OF|IN object */
#line 714 "pikchr.y"
																																																																																																																															 {yylhsminor.yy138 = pik_find_nth(p,yymsp[0].minor.yy138,&yymsp[-2].minor.yy0);}
#line 2854 "pikchr.c"
																																																																																																																															   yymsp[-2].minor.yy138 = yylhsminor.yy138;
																																																																																																																															           break;
																																																																																																																																         case 87: /* objectname ::= PLACENAME */
#line 716 "pikchr.y"
																																																																																																																																   {yylhsminor.yy138 = pik_find_byname(p,0,&yymsp[0].minor.yy0);}
#line 2860 "pikchr.c"
																																																																																																																																     yymsp[0].minor.yy138 = yylhsminor.yy138;
																																																																																																																																             break;
																																																																																																																																	           case 88: /* objectname ::= objectname DOT_U PLACENAME */
#line 718 "pikchr.y"
																																																																																																																																	     {yylhsminor.yy138 = pik_find_byname(p,yymsp[-2].minor.yy138,&yymsp[0].minor.yy0);}
#line 2866 "pikchr.c"
																																																																																																																																	       yymsp[-2].minor.yy138 = yylhsminor.yy138;
																																																																																																																																	               break;
																																																																																																																																		             case 89: /* nth ::= NTH CLASSNAME */
#line 720 "pikchr.y"
																																																																																																																																		       {yylhsminor.yy0=yymsp[0].minor.yy0; yylhsminor.yy0.eCode = pik_nth_value(p,&yymsp[-1].minor.yy0); }
#line 2872 "pikchr.c"
																																																																																																																																		         yymsp[-1].minor.yy0 = yylhsminor.yy0;
																																																																																																																																			         break;
																																																																																																																																				       case 90: /* nth ::= NTH LAST CLASSNAME */
#line 721 "pikchr.y"
																																																																																																																																				 {yylhsminor.yy0=yymsp[0].minor.yy0; yylhsminor.yy0.eCode = -pik_nth_value(p,&yymsp[-2].minor.yy0); }
#line 2878 "pikchr.c"
																																																																																																																																				   yymsp[-2].minor.yy0 = yylhsminor.yy0;
																																																																																																																																				           break;
																																																																																																																																					         case 91: /* nth ::= LAST CLASSNAME */
#line 722 "pikchr.y"
																																																																																																																																					   {yymsp[-1].minor.yy0=yymsp[0].minor.yy0; yymsp[-1].minor.yy0.eCode = -1;}
#line 2884 "pikchr.c"
																																																																																																																																					           break;
																																																																																																																																						         case 92: /* nth ::= LAST */
#line 723 "pikchr.y"
																																																																																																																																						   {yylhsminor.yy0=yymsp[0].minor.yy0; yylhsminor.yy0.eCode = -1;}
#line 2889 "pikchr.c"
																																																																																																																																						     yymsp[0].minor.yy0 = yylhsminor.yy0;
																																																																																																																																						             break;
																																																																																																																																							           case 93: /* nth ::= NTH LB RB */
#line 724 "pikchr.y"
																																																																																																																																							     {yylhsminor.yy0=yymsp[-1].minor.yy0; yylhsminor.yy0.eCode = pik_nth_value(p,&yymsp[-2].minor.yy0);}
#line 2895 "pikchr.c"
																																																																																																																																							       yymsp[-2].minor.yy0 = yylhsminor.yy0;
																																																																																																																																							               break;
																																																																																																																																								             case 94: /* nth ::= NTH LAST LB RB */
#line 725 "pikchr.y"
																																																																																																																																								       {yylhsminor.yy0=yymsp[-1].minor.yy0; yylhsminor.yy0.eCode = -pik_nth_value(p,&yymsp[-3].minor.yy0);}
#line 2901 "pikchr.c"
																																																																																																																																								         yymsp[-3].minor.yy0 = yylhsminor.yy0;
																																																																																																																																									         break;
																																																																																																																																										       case 95: /* nth ::= LAST LB RB */
#line 726 "pikchr.y"
																																																																																																																																										 {yymsp[-2].minor.yy0=yymsp[-1].minor.yy0; yymsp[-2].minor.yy0.eCode = -1; }
#line 2907 "pikchr.c"
																																																																																																																																										         break;
																																																																																																																																											       case 96: /* expr ::= expr PLUS expr */
#line 728 "pikchr.y"
																																																																																																																																											 {yylhsminor.yy121=yymsp[-2].minor.yy121+yymsp[0].minor.yy121;}
#line 2912 "pikchr.c"
																																																																																																																																											   yymsp[-2].minor.yy121 = yylhsminor.yy121;
																																																																																																																																											           break;
																																																																																																																																												         case 97: /* expr ::= expr MINUS expr */
#line 729 "pikchr.y"
																																																																																																																																												   {yylhsminor.yy121=yymsp[-2].minor.yy121-yymsp[0].minor.yy121;}
#line 2918 "pikchr.c"
																																																																																																																																												     yymsp[-2].minor.yy121 = yylhsminor.yy121;
																																																																																																																																												             break;
																																																																																																																																													           case 98: /* expr ::= expr STAR expr */
#line 730 "pikchr.y"
																																																																																																																																													     {yylhsminor.yy121=yymsp[-2].minor.yy121*yymsp[0].minor.yy121;}
#line 2924 "pikchr.c"
																																																																																																																																													       yymsp[-2].minor.yy121 = yylhsminor.yy121;
																																																																																																																																													               break;
																																																																																																																																														             case 99: /* expr ::= expr SLASH expr */
#line 731 "pikchr.y"
																																																																																																																																														       {
																																																																																																																																															         if( yymsp[0].minor.yy121==0.0 ){ pik_error(p, &yymsp[-1].minor.yy0, "division by zero"); yylhsminor.yy121 = 0.0; }
																																																																																																																																																   else{ yylhsminor.yy121 = yymsp[-2].minor.yy121/yymsp[0].minor.yy121; }
																																																																																																																																														       }
#line 2933 "pikchr.c"
																																																																																																																																														         yymsp[-2].minor.yy121 = yylhsminor.yy121;
																																																																																																																																															         break;
																																																																																																																																																       case 100: /* expr ::= MINUS expr */
#line 735 "pikchr.y"
																																																																																																																																																 {yymsp[-1].minor.yy121=-yymsp[0].minor.yy121;}
#line 2939 "pikchr.c"
																																																																																																																																																         break;
																																																																																																																																																	       case 101: /* expr ::= PLUS expr */
#line 736 "pikchr.y"
																																																																																																																																																	 {yymsp[-1].minor.yy121=yymsp[0].minor.yy121;}
#line 2944 "pikchr.c"
																																																																																																																																																	         break;
																																																																																																																																																		       case 102: /* expr ::= LP expr RP */
#line 737 "pikchr.y"
																																																																																																																																																		 {yymsp[-2].minor.yy121=yymsp[-1].minor.yy121;}
#line 2949 "pikchr.c"
																																																																																																																																																		         break;
																																																																																																																																																			       case 103: /* expr ::= LP FILL|COLOR|THICKNESS RP */
#line 738 "pikchr.y"
																																																																																																																																																			 {yymsp[-2].minor.yy121=pik_get_var(p,&yymsp[-1].minor.yy0);}
#line 2954 "pikchr.c"
																																																																																																																																																			         break;
																																																																																																																																																				       case 104: /* expr ::= NUMBER */
#line 739 "pikchr.y"
																																																																																																																																																				 {yylhsminor.yy121=pik_atof(&yymsp[0].minor.yy0);}
#line 2959 "pikchr.c"
																																																																																																																																																				   yymsp[0].minor.yy121 = yylhsminor.yy121;
																																																																																																																																																				           break;
																																																																																																																																																					         case 105: /* expr ::= ID */
#line 740 "pikchr.y"
																																																																																																																																																					   {yylhsminor.yy121=pik_get_var(p,&yymsp[0].minor.yy0);}
#line 2965 "pikchr.c"
																																																																																																																																																					     yymsp[0].minor.yy121 = yylhsminor.yy121;
																																																																																																																																																					             break;
																																																																																																																																																						           case 106: /* expr ::= FUNC1 LP expr RP */
#line 741 "pikchr.y"
																																																																																																																																																						     {yylhsminor.yy121 = pik_func(p,&yymsp[-3].minor.yy0,yymsp[-1].minor.yy121,0.0);}
#line 2971 "pikchr.c"
																																																																																																																																																						       yymsp[-3].minor.yy121 = yylhsminor.yy121;
																																																																																																																																																						               break;
																																																																																																																																																							             case 107: /* expr ::= FUNC2 LP expr COMMA expr RP */
#line 742 "pikchr.y"
																																																																																																																																																							       {yylhsminor.yy121 = pik_func(p,&yymsp[-5].minor.yy0,yymsp[-3].minor.yy121,yymsp[-1].minor.yy121);}
#line 2977 "pikchr.c"
																																																																																																																																																							         yymsp[-5].minor.yy121 = yylhsminor.yy121;
																																																																																																																																																								         break;
																																																																																																																																																									       case 108: /* expr ::= DIST LP position COMMA position RP */
#line 743 "pikchr.y"
																																																																																																																																																									 {yymsp[-5].minor.yy121 = pik_dist(&yymsp[-3].minor.yy47,&yymsp[-1].minor.yy47);}
#line 2983 "pikchr.c"
																																																																																																																																																									         break;
																																																																																																																																																										       case 109: /* expr ::= place2 DOT_XY X */
#line 744 "pikchr.y"
																																																																																																																																																										 {yylhsminor.yy121 = yymsp[-2].minor.yy47.x;}
#line 2988 "pikchr.c"
																																																																																																																																																										   yymsp[-2].minor.yy121 = yylhsminor.yy121;
																																																																																																																																																										           break;
																																																																																																																																																											         case 110: /* expr ::= place2 DOT_XY Y */
#line 745 "pikchr.y"
																																																																																																																																																											   {yylhsminor.yy121 = yymsp[-2].minor.yy47.y;}
#line 2994 "pikchr.c"
																																																																																																																																																											     yymsp[-2].minor.yy121 = yylhsminor.yy121;
																																																																																																																																																											             break;
																																																																																																																																																												           case 111: /* expr ::= object DOT_L numproperty */
																																																																																																																																																												           case 112: /* expr ::= object DOT_L dashproperty */ yytestcase(yyruleno==112);
																																																																																																																																																																			            case 113: /* expr ::= object DOT_L colorproperty */ yytestcase(yyruleno==113);
#line 746 "pikchr.y"
																																																																																																																																																																											{yylhsminor.yy121=pik_property_of(yymsp[-2].minor.yy138,&yymsp[0].minor.yy0);}
#line 3002 "pikchr.c"
																																																																																																																																																																											  yymsp[-2].minor.yy121 = yylhsminor.yy121;
																																																																																																																																																																											          break;
																																																																																																																																																																												        default:
																																																																																																																																																																												        /* (114) lvalue ::= ID */ yytestcase(yyruleno==114);
																																																																																																																																																																													      /* (115) lvalue ::= FILL */ yytestcase(yyruleno==115);
																																																																																																																																																																													            /* (116) lvalue ::= COLOR */ yytestcase(yyruleno==116);
																																																																																																																																																																														          /* (117) lvalue ::= THICKNESS */ yytestcase(yyruleno==117);
																																																																																																																																																																															        /* (118) rvalue ::= expr */ yytestcase(yyruleno==118);
																																																																																																																																																																																      /* (119) print ::= PRINT */ yytestcase(yyruleno==119);
																																																																																																																																																																																            /* (120) prlist ::= pritem (OPTIMIZED OUT) */ assert(yyruleno!=120);
																																																																																																																																																																																	          /* (121) prlist ::= prlist prsep pritem */ yytestcase(yyruleno==121);
																																																																																																																																																																																		        /* (122) direction ::= UP */ yytestcase(yyruleno==122);
																																																																																																																																																																																			      /* (123) direction ::= DOWN */ yytestcase(yyruleno==123);
																																																																																																																																																																																			            /* (124) direction ::= LEFT */ yytestcase(yyruleno==124);
																																																																																																																																																																																				          /* (125) direction ::= RIGHT */ yytestcase(yyruleno==125);
																																																																																																																																																																																					        /* (126) optrelexpr ::= relexpr (OPTIMIZED OUT) */ assert(yyruleno!=126);
																																																																																																																																																																																						      /* (127) attribute_list ::= alist */ yytestcase(yyruleno==127);
																																																																																																																																																																																						            /* (128) alist ::= */ yytestcase(yyruleno==128);
																																																																																																																																																																																							          /* (129) alist ::= alist attribute */ yytestcase(yyruleno==129);
																																																																																																																																																																																								        /* (130) attribute ::= boolproperty (OPTIMIZED OUT) */ assert(yyruleno!=130);
																																																																																																																																																																																									      /* (131) attribute ::= WITH withclause */ yytestcase(yyruleno==131);
																																																																																																																																																																																									            /* (132) go ::= GO */ yytestcase(yyruleno==132);
																																																																																																																																																																																										          /* (133) go ::= */ yytestcase(yyruleno==133);
																																																																																																																																																																																											        /* (134) even ::= UNTIL EVEN WITH */ yytestcase(yyruleno==134);
																																																																																																																																																																																												      /* (135) even ::= EVEN WITH */ yytestcase(yyruleno==135);
																																																																																																																																																																																												            /* (136) dashproperty ::= DOTTED */ yytestcase(yyruleno==136);
																																																																																																																																																																																													          /* (137) dashproperty ::= DASHED */ yytestcase(yyruleno==137);
																																																																																																																																																																																														        /* (138) colorproperty ::= FILL */ yytestcase(yyruleno==138);
																																																																																																																																																																																															      /* (139) colorproperty ::= COLOR */ yytestcase(yyruleno==139);
																																																																																																																																																																																															            /* (140) position ::= place */ yytestcase(yyruleno==140);
																																																																																																																																																																																																          /* (141) between ::= WAY BETWEEN */ yytestcase(yyruleno==141);
																																																																																																																																																																																																	        /* (142) between ::= BETWEEN */ yytestcase(yyruleno==142);
																																																																																																																																																																																																		      /* (143) between ::= OF THE WAY BETWEEN */ yytestcase(yyruleno==143);
																																																																																																																																																																																																		            /* (144) place ::= place2 */ yytestcase(yyruleno==144);
																																																																																																																																																																																																			          /* (145) edge ::= CENTER */ yytestcase(yyruleno==145);
																																																																																																																																																																																																				        /* (146) edge ::= EDGEPT */ yytestcase(yyruleno==146);
																																																																																																																																																																																																					      /* (147) edge ::= TOP */ yytestcase(yyruleno==147);
																																																																																																																																																																																																					            /* (148) edge ::= BOTTOM */ yytestcase(yyruleno==148);
																																																																																																																																																																																																						          /* (149) edge ::= START */ yytestcase(yyruleno==149);
																																																																																																																																																																																																							        /* (150) edge ::= END */ yytestcase(yyruleno==150);
																																																																																																																																																																																																								      /* (151) edge ::= RIGHT */ yytestcase(yyruleno==151);
																																																																																																																																																																																																								            /* (152) edge ::= LEFT */ yytestcase(yyruleno==152);
																																																																																																																																																																																																									          /* (153) object ::= objectname */ yytestcase(yyruleno==153);
																																																																																																																																																																																																										          break;
																																																																																																																																																																																																											  /********** End reduce actions ************************************************/
																																																																																																																																																																																																											    };
			        assert( yyruleno<sizeof(yyRuleInfoLhs)/sizeof(yyRuleInfoLhs[0]) );
				  yygoto = yyRuleInfoLhs[yyruleno];
				    yysize = yyRuleInfoNRhs[yyruleno];
				      yyact = yy_find_reduce_action(yymsp[yysize].stateno,(YYCODETYPE)yygoto);

				        /* There are no SHIFTREDUCE actions on nonterminals because the table
					 *   ** generator has simplified them to pure REDUCE actions. */
				        assert( !(yyact>YY_MAX_SHIFT && yyact<=YY_MAX_SHIFTREDUCE) );

					  /* It is not possible for a REDUCE to be followed by an error */
					  assert( yyact!=YY_ERROR_ACTION );

					    yymsp += yysize+1;
					      yypParser->yytos = yymsp;
					        yymsp->stateno = (YYACTIONTYPE)yyact;
						  yymsp->major = (YYCODETYPE)yygoto;
						    yyTraceShift(yypParser, yyact, "... then shift");
						      return yyact;
}

/*
 * ** The following code executes when the parse fails
 * */
#ifndef YYNOERRORRECOVERY
static void yy_parse_failed(
		  yyParser *yypParser           /* The parser */
		){
	  pik_parserARG_FETCH
		    pik_parserCTX_FETCH
#ifndef NDEBUG
		      if( yyTraceFILE ){
			          fprintf(yyTraceFILE,"%sFail!\n",yyTracePrompt);
				    }
#endif
	    while( yypParser->yytos>yypParser->yystack ) yy_pop_parser_stack(yypParser);
	    /* Here code is inserted which will be executed whenever the
	     *   ** parser fails */
	  /************ Begin %parse_failure code ***************************************/
	  /************ End %parse_failure code *****************************************/
	    pik_parserARG_STORE /* Suppress warning about unused %extra_argument variable */
		      pik_parserCTX_STORE
}
#endif /* YYNOERRORRECOVERY */

/*
 * ** The following code executes when a syntax error first occurs.
 * */
static void yy_syntax_error(
		  yyParser *yypParser,           /* The parser */
		    int yymajor,                   /* The major type of the error token */
		      pik_parserTOKENTYPE yyminor         /* The minor type of the error token */
		){
	  pik_parserARG_FETCH
		    pik_parserCTX_FETCH
#define TOKEN yyminor
		    /************ Begin %syntax_error code ****************************************/
#line 509 "pikchr.y"

		      if( TOKEN.z && TOKEN.z[0] ){
			          pik_error(p, &TOKEN, "syntax error");
				    }else{
					        pik_error(p, 0, "syntax error");
						  }
	    UNUSED_PARAMETER(yymajor);
#line 3113 "pikchr.c"
	    /************ End %syntax_error code ******************************************/
	      pik_parserARG_STORE /* Suppress warning about unused %extra_argument variable */
		        pik_parserCTX_STORE
}

/*
 * ** The following is executed when the parser accepts
 * */
static void yy_accept(
		  yyParser *yypParser           /* The parser */
		){
	  pik_parserARG_FETCH
		    pik_parserCTX_FETCH
#ifndef NDEBUG
		      if( yyTraceFILE ){
			          fprintf(yyTraceFILE,"%sAccept!\n",yyTracePrompt);
				    }
#endif
#ifndef YYNOERRORRECOVERY
	    yypParser->yyerrcnt = -1;
#endif
	      assert( yypParser->yytos==yypParser->yystack );
	        /* Here code is inserted which will be executed whenever the
		 *   ** parser accepts */
	      /*********** Begin %parse_accept code *****************************************/
	      /*********** End %parse_accept code *******************************************/
	        pik_parserARG_STORE /* Suppress warning about unused %extra_argument variable */
			  pik_parserCTX_STORE
}

/* The main parser program.
 * ** The first argument is a pointer to a structure obtained from
 * ** "pik_parserAlloc" which describes the current state of the parser.
 * ** The second argument is the major token number.  The third is
 * ** the minor token.  The fourth optional argument is whatever the
 * ** user wants (and specified in the grammar) and is available for
 * ** use by the action routines.
 * **
 * ** Inputs:
 * ** <ul>
 * ** <li> A pointer to the parser (an opaque structure.)
 * ** <li> The major token number.
 * ** <li> The minor token number.
 * ** <li> An option argument of a grammar-specified type.
 * ** </ul>
 * **
 * ** Outputs:
 * ** None.
 * */
void pik_parser(
		  void *yyp,                   /* The parser */
		    int yymajor,                 /* The major token code number */
		      pik_parserTOKENTYPE yyminor       /* The value for the token */
		        pik_parserARG_PDECL               /* Optional %extra_argument parameter */
	       ){
	  YYMINORTYPE yyminorunion;
	    YYACTIONTYPE yyact;   /* The parser action. */
#if !defined(YYERRORSYMBOL) && !defined(YYNOERRORRECOVERY)
	      int yyendofinput;     /* True if we are at the end of input */
#endif
#ifdef YYERRORSYMBOL
	        int yyerrorhit = 0;   /* True if yymajor has invoked an error */
#endif
		  yyParser *yypParser = (yyParser*)yyp;  /* The parser */
		    pik_parserCTX_FETCH
			      pik_parserARG_STORE

			        assert( yypParser->yytos!=0 );
#if !defined(YYERRORSYMBOL) && !defined(YYNOERRORRECOVERY)
		      yyendofinput = (yymajor==0);
#endif

		        yyact = yypParser->yytos->stateno;
#ifndef NDEBUG
			  if( yyTraceFILE ){
				      if( yyact < YY_MIN_REDUCE ){
					            fprintf(yyTraceFILE,"%sInput '%s' in state %d\n",
								                  yyTracePrompt,yyTokenName[yymajor],yyact);
						        }else{
								      fprintf(yyTraceFILE,"%sInput '%s' with pending reduce %d\n",
										                    yyTracePrompt,yyTokenName[yymajor],yyact-YY_MIN_REDUCE);
								          }
				        }
#endif

			    do{
				        assert( yyact==yypParser->yytos->stateno );
					    yyact = yy_find_shift_action((YYCODETYPE)yymajor,yyact);
					        if( yyact >= YY_MIN_REDUCE ){
							      yyact = yy_reduce(yypParser,yyact-YY_MIN_REDUCE,yymajor,
									                              yyminor pik_parserCTX_PARAM);
							          }else if( yyact <= YY_MAX_SHIFTREDUCE ){
									        yy_shift(yypParser,yyact,(YYCODETYPE)yymajor,yyminor);
#ifndef YYNOERRORRECOVERY
										      yypParser->yyerrcnt--;
#endif
										            break;
											        }else if( yyact==YY_ACCEPT_ACTION ){
													      yypParser->yytos--;
													            yy_accept(yypParser);
														          return;
															      }else{
																            assert( yyact == YY_ERROR_ACTION );
																	          yyminorunion.yy0 = yyminor;
#ifdef YYERRORSYMBOL
																		        int yymx;
#endif
#ifndef NDEBUG
																			      if( yyTraceFILE ){
																				              fprintf(yyTraceFILE,"%sSyntax Error!\n",yyTracePrompt);
																					            }
#endif
#ifdef YYERRORSYMBOL
																			            /* A syntax error has occurred.
																				     *       ** The response to an error depends upon whether or not the
																				     *             ** grammar defines an error token "ERROR".  
																				     *                   **
																				     *                         ** This is what we do if the grammar does define ERROR:
																				     *                               **
																				     *                                     **  * Call the %syntax_error function.
																				     *                                           **
																				     *                                                 **  * Begin popping the stack until we enter a state where
																				     *                                                       **    it is legal to shift the error symbol, then shift
																				     *                                                             **    the error symbol.
																				     *                                                                   **
																				     *                                                                         **  * Set the error count to three.
																				     *                                                                               **
																				     *                                                                                     **  * Begin accepting and shifting new tokens.  No new error
																				     *                                                                                           **    processing will occur until three tokens have been
																				     *                                                                                                 **    shifted successfully.
																				     *                                                                                                       **
																				     *                                                                                                             */
																			            if( yypParser->yyerrcnt<0 ){
																					            yy_syntax_error(yypParser,yymajor,yyminor);
																						          }
																				          yymx = yypParser->yytos->major;
																					        if( yymx==YYERRORSYMBOL || yyerrorhit ){
#ifndef NDEBUG
																							        if( yyTraceFILE ){
																									          fprintf(yyTraceFILE,"%sDiscard input token %s\n",
																												               yyTracePrompt,yyTokenName[yymajor]);
																										          }
#endif
																								        yy_destructor(yypParser, (YYCODETYPE)yymajor, &yyminorunion);
																									        yymajor = YYNOCODE;
																										      }else{
																											              while( yypParser->yytos >= yypParser->yystack
																														                  && (yyact = yy_find_reduce_action(
																																		                          yypParser->yytos->stateno,
																																					                          YYERRORSYMBOL)) > YY_MAX_SHIFTREDUCE
																																          ){
																													                yy_pop_parser_stack(yypParser);
																															        }
																												              if( yypParser->yytos < yypParser->yystack || yymajor==0 ){
																														                yy_destructor(yypParser,(YYCODETYPE)yymajor,&yyminorunion);
																																          yy_parse_failed(yypParser);
#ifndef YYNOERRORRECOVERY
																																	            yypParser->yyerrcnt = -1;
#endif
																																		              yymajor = YYNOCODE;
																																			              }else if( yymx!=YYERRORSYMBOL ){
																																					                yy_shift(yypParser,yyact,YYERRORSYMBOL,yyminor);
																																							        }
																													            }
																						      yypParser->yyerrcnt = 3;
																						            yyerrorhit = 1;
																							          if( yymajor==YYNOCODE ) break;
																								        yyact = yypParser->yytos->stateno;
#elif defined(YYNOERRORRECOVERY)
																									      /* If the YYNOERRORRECOVERY macro is defined, then do not attempt to
																									       *       ** do any kind of error recovery.  Instead, simply invoke the syntax
																									       *             ** error routine and continue going as if nothing had happened.
																									       *                   **
																									       *                         ** Applications can set this macro (for example inside %include) if
																									       *                               ** they intend to abandon the parse upon the first syntax error seen.
																									       *                                     */
																									      yy_syntax_error(yypParser,yymajor, yyminor);
																									            yy_destructor(yypParser,(YYCODETYPE)yymajor,&yyminorunion);
																										          break;
#else  /* YYERRORSYMBOL is not defined */
																											        /* This is what we do if the grammar does not define ERROR:
																												 *       **
																												 *             **  * Report an error message, and throw away the input token.
																												 *                   **
																												 *                         **  * If the input token is $, then fail the parse.
																												 *                               **
																												 *                                     ** As before, subsequent error messages are suppressed until
																												 *                                           ** three input tokens have been successfully shifted.
																												 *                                                 */
																											        if( yypParser->yyerrcnt<=0 ){
																													        yy_syntax_error(yypParser,yymajor, yyminor);
																														      }
																												      yypParser->yyerrcnt = 3;
																												            yy_destructor(yypParser,(YYCODETYPE)yymajor,&yyminorunion);
																													          if( yyendofinput ){
																															          yy_parse_failed(yypParser);
#ifndef YYNOERRORRECOVERY
																																          yypParser->yyerrcnt = -1;
#endif
																																	        }
																														        break;
#endif
																															    }
						  }while( yypParser->yytos>yypParser->yystack );
#ifndef NDEBUG
			      if( yyTraceFILE ){
				          yyStackEntry *i;
					      char cDiv = '[';
					          fprintf(yyTraceFILE,"%sReturn. Stack=",yyTracePrompt);
						      for(i=&yypParser->yystack[1]; i<=yypParser->yytos; i++){
							            fprintf(yyTraceFILE,"%c%s", cDiv, yyTokenName[i->major]);
								          cDiv = ' ';
									      }
						          fprintf(yyTraceFILE,"]\n");
							    }
#endif
			      return;
}

/*
 * ** Return the fallback token corresponding to canonical token iToken, or
 * ** 0 if iToken has no fallback.
 * */
int pik_parserFallback(int iToken){
#ifdef YYFALLBACK
	  assert( iToken<(int)(sizeof(yyFallback)/sizeof(yyFallback[0])) );
	    return yyFallback[iToken];
#else
	      (void)iToken;
	        return 0;
#endif
}
#line 751 "pikchr.y"



/* Chart of the 140 official HTML color names with their
 * ** corresponding RGB value.
 * **
 * ** Two new names "None" and "Off" are added with a value
 * ** of -1.
 * */
static const struct {
	  const char *zName;  /* Name of the color */
	    int val;            /* RGB value */
} aColor[] = {
	  { "AliceBlue",                   0xf0f8ff },
	    { "AntiqueWhite",                0xfaebd7 },
	      { "Aqua",                        0x00ffff },
	        { "AquaMarine",                  0x7fffd4 },
		  { "Azure",                       0xf0ffff },
		    { "Beige",                       0xf5f5dc },
		      { "Bisque",                      0xffe4c4 },
		        { "Black",                       0x000000 },
			  { "BlanchedAlmond",              0xffebcd },
			    { "Blue",                        0x0000ff },
			      { "BlueViolet",                  0x8a2be2 },
			        { "Brown",                       0xa52a2a },
				  { "BurlyWood",                   0xdeb887 },
				    { "CadetBlue",                   0x5f9ea0 },
				      { "Chartreuse",                  0x7fff00 },
				        { "Chocolate",                   0xd2691e },
					  { "Coral",                       0xff7f50 },
					    { "CornFlowerBlue",              0x6495ed },
					      { "Cornsilk",                    0xfff8dc },
					        { "Crimson",                     0xdc143c },
						  { "Cyan",                        0x00ffff },
						    { "DarkBlue",                    0x00008b },
						      { "DarkCyan",                    0x008b8b },
						        { "DarkGoldenRod",               0xb8860b },
							  { "DarkGray",                    0xa9a9a9 },
							    { "DarkGreen",                   0x006400 },
							      { "DarkKhaki",                   0xbdb76b },
							        { "DarkMagenta",                 0x8b008b },
								  { "DarkOliveGreen",              0x556b2f },
								    { "DarkOrange",                  0xff8c00 },
								      { "DarkOrchid",                  0x9932cc },
								        { "DarkRed",                     0x8b0000 },
									  { "DarkSalmon",                  0xe9967a },
									    { "DarkSeaGreen",                0x8fbc8f },
									      { "DarkSlateBlue",               0x483d8b },
									        { "DarkSlateGray",               0x2f4f4f },
										  { "DarkTurquoise",               0x00ced1 },
										    { "DarkViolet",                  0x9400d3 },
										      { "DeepPink",                    0xff1493 },
										        { "DeepSkyBlue",                 0x00bfff },
											  { "DimGray",                     0x696969 },
											    { "DodgerBlue",                  0x1e90ff },
											      { "FireBrick",                   0xb22222 },
											        { "FloralWhite",                 0xfffaf0 },
												  { "ForestGreen",                 0x228b22 },
												    { "Fuchsia",                     0xff00ff },
												      { "Gainsboro",                   0xdcdcdc },
												        { "GhostWhite",                  0xf8f8ff },
													  { "Gold",                        0xffd700 },
													    { "GoldenRod",                   0xdaa520 },
													      { "Gray",                        0x808080 },
													        { "Green",                       0x008000 },
														  { "GreenYellow",                 0xadff2f },
														    { "HoneyDew",                    0xf0fff0 },
														      { "HotPink",                     0xff69b4 },
														        { "IndianRed",                   0xcd5c5c },
															  { "Indigo",                      0x4b0082 },
															    { "Ivory",                       0xfffff0 },
															      { "Khaki",                       0xf0e68c },
															        { "Lavender",                    0xe6e6fa },
																  { "LavenderBlush",               0xfff0f5 },
																    { "LawnGreen",                   0x7cfc00 },
																      { "LemonChiffon",                0xfffacd },
																        { "LightBlue",                   0xadd8e6 },
																	  { "LightCoral",                  0xf08080 },
																	    { "LightCyan",                   0xe0ffff },
																	      { "LightGoldenrodYellow",        0xfafad2 },
																	        { "LightGray",                   0xd3d3d3 },
																		  { "LightGreen",                  0x90ee90 },
																		    { "LightPink",                   0xffb6c1 },
																		      { "LightSalmon",                 0xffa07a },
																		        { "LightSeaGreen",               0x20b2aa },
																			  { "LightSkyBlue",                0x87cefa },
																			    { "LightSlateGray",              0x778899 },
																			      { "LightSteelBlue",              0xb0c4de },
																			        { "LightYellow",                 0xffffe0 },
																				  { "Lime",                        0x00ff00 },
																				    { "LimeGreen",                   0x32cd32 },
																				      { "Linen",                       0xfaf0e6 },
																				        { "Magenta",                     0xff00ff },
																					  { "Maroon",                      0x800000 },
																					    { "MediumAquaMarine",            0x66cdaa },
																					      { "MediumBlue",                  0x0000cd },
																					        { "MediumOrchid",                0xba55d3 },
																						  { "MediumPurple",                0x9370d8 },
																						    { "MediumSeaGreen",              0x3cb371 },
																						      { "MediumSlateBlue",             0x7b68ee },
																						        { "MediumSpringGreen",           0x00fa9a },
																							  { "MediumTurquoise",             0x48d1cc },
																							    { "MediumVioletRed",             0xc71585 },
																							      { "MidnightBlue",                0x191970 },
																							        { "MintCream",                   0xf5fffa },
																								  { "MistyRose",                   0xffe4e1 },
																								    { "Moccasin",                    0xffe4b5 },
																								      { "NavajoWhite",                 0xffdead },
																								        { "Navy",                        0x000080 },
																									  { "None",                              -1 },  /* Non-standard addition */
																									    { "Off",                               -1 },  /* Non-standard addition */
																									      { "OldLace",                     0xfdf5e6 },
																									        { "Olive",                       0x808000 },
																										  { "OliveDrab",                   0x6b8e23 },
																										    { "Orange",                      0xffa500 },
																										      { "OrangeRed",                   0xff4500 },
																										        { "Orchid",                      0xda70d6 },
																											  { "PaleGoldenRod",               0xeee8aa },
																											    { "PaleGreen",                   0x98fb98 },
																											      { "PaleTurquoise",               0xafeeee },
																											        { "PaleVioletRed",               0xdb7093 },
																												  { "PapayaWhip",                  0xffefd5 },
																												    { "PeachPuff",                   0xffdab9 },
																												      { "Peru",                        0xcd853f },
																												        { "Pink",                        0xffc0cb },
																													  { "Plum",                        0xdda0dd },
																													    { "PowderBlue",                  0xb0e0e6 },
																													      { "Purple",                      0x800080 },
																													        { "Red",                         0xff0000 },
																														  { "RosyBrown",                   0xbc8f8f },
																														    { "RoyalBlue",                   0x4169e1 },
																														      { "SaddleBrown",                 0x8b4513 },
																														        { "Salmon",                      0xfa8072 },
																															  { "SandyBrown",                  0xf4a460 },
																															    { "SeaGreen",                    0x2e8b57 },
																															      { "SeaShell",                    0xfff5ee },
																															        { "Sienna",                      0xa0522d },
																																  { "Silver",                      0xc0c0c0 },
																																    { "SkyBlue",                     0x87ceeb },
																																      { "SlateBlue",                   0x6a5acd },
																																        { "SlateGray",                   0x708090 },
																																	  { "Snow",                        0xfffafa },
																																	    { "SpringGreen",                 0x00ff7f },
																																	      { "SteelBlue",                   0x4682b4 },
																																	        { "Tan",                         0xd2b48c },
																																		  { "Teal",                        0x008080 },
																																		    { "Thistle",                     0xd8bfd8 },
																																		      { "Tomato",                      0xff6347 },
																																		        { "Turquoise",                   0x40e0d0 },
																																			  { "Violet",                      0xee82ee },
																																			    { "Wheat",                       0xf5deb3 },
																																			      { "White",                       0xffffff },
																																			        { "WhiteSmoke",                  0xf5f5f5 },
																																				  { "Yellow",                      0xffff00 },
																																				    { "YellowGreen",                 0x9acd32 },
};

/* Built-in variable names.
 * **
 * ** This array is constant.  When a script changes the value of one of
 * ** these built-ins, a new PVar record is added at the head of
 * ** the Pik.pVar list, which is searched first.  Thus the new PVar entry
 * ** will override this default value.
 * **
 * ** Units are in inches, except for "color" and "fill" which are 
 * ** interpreted as 24-bit RGB values.
 * **
 * ** Binary search used.  Must be kept in sorted order.
 * */
static const struct { const char *zName; PNum val; } aBuiltin[] = {
	  { "arcrad",      0.25  },
	    { "arrowhead",   2.0   },
	      { "arrowht",     0.08  },
	        { "arrowwid",    0.06  },
		  { "boxht",       0.5   },
		    { "boxrad",      0.0   },
		      { "boxwid",      0.75  },
		        { "charht",      0.14  },
			  { "charwid",     0.08  },
			    { "circlerad",   0.25  },
			      { "color",       0.0   },
			        { "cylht",       0.5   },
				  { "cylrad",      0.075 },
				    { "cylwid",      0.75  },
				      { "dashwid",     0.05  },
				        { "dotrad",      0.015 },
					  { "ellipseht",   0.5   },
					    { "ellipsewid",  0.75  },
					      { "fileht",      0.75  },
					        { "filerad",     0.15  },
						  { "filewid",     0.5   },
						    { "fill",        -1.0  },
						      { "lineht",      0.5   },
						        { "linewid",     0.5   },
							  { "movewid",     0.5   },
							    { "ovalht",      0.5   },
							      { "ovalwid",     1.0   },
							        { "scale",       1.0   },
								  { "textht",      0.5   },
								    { "textwid",     0.75  },
								      { "thickness",   0.015 },
};


/* Methods for the "arc" class */
static void arcInit(Pik *p, PObj *pObj){
	  pObj->w = pik_value(p, "arcrad",6,0);
	    pObj->h = pObj->w;
}
/* Hack: Arcs are here rendered as quadratic Bezier curves rather
 * ** than true arcs.  Multiple reasons: (1) the legacy-PIC parameters
 * ** that control arcs are obscure and I could not figure out what they
 * ** mean based on available documentation.  (2) Arcs are rarely used,
 * ** and so do not seem that important.
 * */
static PPoint arcControlPoint(int cw, PPoint f, PPoint t, PNum rScale){
	  PPoint m;
	    PNum dx, dy;
	      m.x = 0.5*(f.x+t.x);
	        m.y = 0.5*(f.y+t.y);
		  dx = t.x - f.x;
		    dy = t.y - f.y;
		      if( cw ){
			          m.x -= 0.5*rScale*dy;
				      m.y += 0.5*rScale*dx;
				        }else{
						    m.x += 0.5*rScale*dy;
						        m.y -= 0.5*rScale*dx;
							  }
		        return m;
}
static void arcCheck(Pik *p, PObj *pObj){
	  PPoint m;
	    if( p->nTPath>2 ){
		        pik_error(p, &pObj->errTok, "arc geometry error");
			    return;
			      }
	      m = arcControlPoint(pObj->cw, p->aTPath[0], p->aTPath[1], 0.5);
	        pik_bbox_add_xy(&pObj->bbox, m.x, m.y);
}
static void arcRender(Pik *p, PObj *pObj){
	  PPoint f, m, t;
	    if( pObj->nPath<2 ) return;
	      if( pObj->sw<=0.0 ) return;
	        f = pObj->aPath[0];
		  t = pObj->aPath[1];
		    m = arcControlPoint(pObj->cw,f,t,1.0);
		      if( pObj->larrow ){
			          pik_draw_arrowhead(p,&m,&f,pObj);
				    }
		        if( pObj->rarrow ){
				    pik_draw_arrowhead(p,&m,&t,pObj);
				      }
			  pik_append_xy(p,"<path d=\"M", f.x, f.y);
			    pik_append_xy(p,"Q", m.x, m.y);
			      pik_append_xy(p," ", t.x, t.y);
			        pik_append(p,"\" ",2);
				  pik_append_style(p,pObj,0);
				    pik_append(p,"\" />\n", -1);

				      pik_append_txt(p, pObj, 0);
}


/* Methods for the "arrow" class */
static void arrowInit(Pik *p, PObj *pObj){
	  pObj->w = pik_value(p, "linewid",7,0);
	    pObj->h = pik_value(p, "lineht",6,0);
	      pObj->rad = pik_value(p, "linerad",7,0);
	        pObj->fill = -1.0;
		  pObj->rarrow = 1;
}

/* Methods for the "box" class */
static void boxInit(Pik *p, PObj *pObj){
	  pObj->w = pik_value(p, "boxwid",6,0);
	    pObj->h = pik_value(p, "boxht",5,0);
	      pObj->rad = pik_value(p, "boxrad",6,0);
}
/* Return offset from the center of the box to the compass point 
 * ** given by parameter cp */
static PPoint boxOffset(Pik *p, PObj *pObj, int cp){
	  PPoint pt = cZeroPoint;
	    PNum w2 = 0.5*pObj->w;
	      PNum h2 = 0.5*pObj->h;
	        PNum rad = pObj->rad;
		  PNum rx;
		    if( rad<=0.0 ){
			        rx = 0.0;
				  }else{
					      if( rad>w2 ) rad = w2;
					          if( rad>h2 ) rad = h2;
						      rx = 0.29289321881345252392*rad;
						        }
		      switch( cp ){
			          case CP_C:                                   break;
									           case CP_N:   pt.x = 0.0;      pt.y = h2;     break;
												    case CP_NE:  pt.x = w2-rx;    pt.y = h2-rx;  break;
														     case CP_E:   pt.x = w2;       pt.y = 0.0;    break;
																      case CP_SE:  pt.x = w2-rx;    pt.y = rx-h2;  break;
																		       case CP_S:   pt.x = 0.0;      pt.y = -h2;    break;
																				        case CP_SW:  pt.x = rx-w2;    pt.y = rx-h2;  break;
																						         case CP_W:   pt.x = -w2;      pt.y = 0.0;    break;
																								          case CP_NW:  pt.x = rx-w2;    pt.y = h2-rx;  break;
																										           default:     assert(0);
																													  }
		        UNUSED_PARAMETER(p);
			  return pt;
}
static PPoint boxChop(Pik *p, PObj *pObj, PPoint *pPt){
	  PNum dx, dy;
	    int cp = CP_C;
	      PPoint chop = pObj->ptAt;
	        if( pObj->w<=0.0 ) return chop;
		  if( pObj->h<=0.0 ) return chop;
		    dx = (pPt->x - pObj->ptAt.x)*pObj->h/pObj->w;
		      dy = (pPt->y - pObj->ptAt.y);
		        if( dx>0.0 ){
				    if( dy>=2.414*dx ){
					          cp = CP_N;
						      }else if( dy>=0.414*dx ){
							            cp = CP_NE;
								        }else if( dy>=-0.414*dx ){
										      cp = CP_E;
										          }else if( dy>-2.414*dx ){
												        cp = CP_SE;
													    }else{
														          cp = CP_S;
															      }
				      }else{
					          if( dy>=-2.414*dx ){
							        cp = CP_N;
								    }else if( dy>=-0.414*dx ){
									          cp = CP_NW;
										      }else if( dy>=0.414*dx ){
											            cp = CP_W;
												        }else if( dy>2.414*dx ){
														      cp = CP_SW;
														          }else{
																        cp = CP_S;
																	    }
						    }
			  chop = pObj->type->xOffset(p,pObj,cp);
			    chop.x += pObj->ptAt.x;
			      chop.y += pObj->ptAt.y;
			        return chop;
}
static void boxFit(Pik *p, PObj *pObj, PNum w, PNum h){
	  if( w>0 ) pObj->w = w;
	    if( h>0 ) pObj->h = h;
	      UNUSED_PARAMETER(p);
}
static void boxRender(Pik *p, PObj *pObj){
	  PNum w2 = 0.5*pObj->w;
	    PNum h2 = 0.5*pObj->h;
	      PNum rad = pObj->rad;
	        PPoint pt = pObj->ptAt;
		  if( pObj->sw>0.0 ){
			      if( rad<=0.0 ){
				            pik_append_xy(p,"<path d=\"M", pt.x-w2,pt.y-h2);
					          pik_append_xy(p,"L", pt.x+w2,pt.y-h2);
						        pik_append_xy(p,"L", pt.x+w2,pt.y+h2);
							      pik_append_xy(p,"L", pt.x-w2,pt.y+h2);
							            pik_append(p,"Z\" ",-1);
								        }else{
										      /*
										       *       **         ----       - y3
										       *             **        /    \
										       *                   **       /      \     _ y2
										       *                         **      |        |    
										       *                               **      |        |    _ y1
										       *                                     **       \      /
										       *                                           **        \    /
										       *                                                 **         ----       _ y0
										       *                                                       **
										       *                                                             **      '  '  '  '
										       *                                                                   **     x0 x1 x2 x3
										       *                                                                         */
										      PNum x0,x1,x2,x3,y0,y1,y2,y3;
										            if( rad>w2 ) rad = w2;
											          if( rad>h2 ) rad = h2;
												        x0 = pt.x - w2;
													      x1 = x0 + rad;
													            x3 = pt.x + w2;
														          x2 = x3 - rad;
															        y0 = pt.y - h2;
																      y1 = y0 + rad;
																            y3 = pt.y + h2;
																	          y2 = y3 - rad;
																		        pik_append_xy(p,"<path d=\"M", x1, y0);
																			      if( x2>x1 ) pik_append_xy(p, "L", x2, y0);
																			            pik_append_arc(p, rad, rad, x3, y1);
																				          if( y2>y1 ) pik_append_xy(p, "L", x3, y2);
																					        pik_append_arc(p, rad, rad, x2, y3);
																						      if( x2>x1 ) pik_append_xy(p, "L", x1, y3);
																						            pik_append_arc(p, rad, rad, x0, y2);
																							          if( y2>y1 ) pik_append_xy(p, "L", x0, y1);
																								        pik_append_arc(p, rad, rad, x1, y0);
																									      pik_append(p,"Z\" ",-1);
																									          }
			          pik_append_style(p,pObj,1);
				      pik_append(p,"\" />\n", -1);
				        }
		    pik_append_txt(p, pObj, 0);
}

/* Methods for the "circle" class */
static void circleInit(Pik *p, PObj *pObj){
	  pObj->w = pik_value(p, "circlerad",9,0)*2;
	    pObj->h = pObj->w;
	      pObj->rad = 0.5*pObj->w;
}
static void circleNumProp(Pik *p, PObj *pObj, PToken *pId){
	  /* For a circle, the width must equal the height and both must
	   *   ** be twice the radius.  Enforce those constraints. */
	  switch( pId->eType ){
		      case T_RADIUS:
			            pObj->w = pObj->h = 2.0*pObj->rad;
				          break;
					      case T_WIDTH:
					        pObj->h = pObj->w;
						      pObj->rad = 0.5*pObj->w;
						            break;
							        case T_HEIGHT:
							          pObj->w = pObj->h;
								        pObj->rad = 0.5*pObj->w;
									      break;
									        }
	    UNUSED_PARAMETER(p);
}
static PPoint circleChop(Pik *p, PObj *pObj, PPoint *pPt){
	  PPoint chop;
	    PNum dx = pPt->x - pObj->ptAt.x;
	      PNum dy = pPt->y - pObj->ptAt.y;
	        PNum dist = hypot(dx,dy);
		  if( dist<pObj->rad ) return pObj->ptAt;
		    chop.x = pObj->ptAt.x + dx*pObj->rad/dist;
		      chop.y = pObj->ptAt.y + dy*pObj->rad/dist;
		        UNUSED_PARAMETER(p);
			  return chop;
}
static void circleFit(Pik *p, PObj *pObj, PNum w, PNum h){
	  PNum mx = 0.0;
	    if( w>0 ) mx = w;
	      if( h>mx ) mx = h;
	        if( w*h>0 && (w*w + h*h) > mx*mx ){
			    mx = hypot(w,h);
			      }
		  if( mx>0.0 ){
			      pObj->rad = 0.5*mx;
			          pObj->w = pObj->h = mx;
				    }
		    UNUSED_PARAMETER(p);
}

static void circleRender(Pik *p, PObj *pObj){
	  PNum r = pObj->rad;
	    PPoint pt = pObj->ptAt;
	      if( pObj->sw>0.0 ){
		          pik_append_x(p,"<circle cx=\"", pt.x, "\"");
			      pik_append_y(p," cy=\"", pt.y, "\"");
			          pik_append_dis(p," r=\"", r, "\" ");
				      pik_append_style(p,pObj,1);
				          pik_append(p,"\" />\n", -1);
					    }
	        pik_append_txt(p, pObj, 0);
}

/* Methods for the "cylinder" class */
static void cylinderInit(Pik *p, PObj *pObj){
	  pObj->w = pik_value(p, "cylwid",6,0);
	    pObj->h = pik_value(p, "cylht",5,0);
	      pObj->rad = pik_value(p, "cylrad",6,0); /* Minor radius of ellipses */
}
static void cylinderFit(Pik *p, PObj *pObj, PNum w, PNum h){
	  if( w>0 ) pObj->w = w;
	    if( h>0 ) pObj->h = h + 4*pObj->rad + pObj->sw;
	      UNUSED_PARAMETER(p);
}
static void cylinderRender(Pik *p, PObj *pObj){
	  PNum w2 = 0.5*pObj->w;
	    PNum h2 = 0.5*pObj->h;
	      PNum rad = pObj->rad;
	        PPoint pt = pObj->ptAt;
		  if( pObj->sw>0.0 ){
			      pik_append_xy(p,"<path d=\"M", pt.x-w2,pt.y+h2-rad);
			          pik_append_xy(p,"L", pt.x-w2,pt.y-h2+rad);
				      pik_append_arc(p,w2,rad,pt.x+w2,pt.y-h2+rad);
				          pik_append_xy(p,"L", pt.x+w2,pt.y+h2-rad);
					      pik_append_arc(p,w2,rad,pt.x-w2,pt.y+h2-rad);
					          pik_append_arc(p,w2,rad,pt.x+w2,pt.y+h2-rad);
						      pik_append(p,"\" ",-1);
						          pik_append_style(p,pObj,1);
							      pik_append(p,"\" />\n", -1);
							        }
		    pik_append_txt(p, pObj, 0);
}
static PPoint cylinderOffset(Pik *p, PObj *pObj, int cp){
	  PPoint pt = cZeroPoint;
	    PNum w2 = pObj->w*0.5;
	      PNum h1 = pObj->h*0.5;
	        PNum h2 = h1 - pObj->rad;
		  switch( cp ){
			      case CP_C:                                break;
									    case CP_N:   pt.x = 0.0;   pt.y = h1;     break;
											     case CP_NE:  pt.x = w2;    pt.y = h2;     break;
													      case CP_E:   pt.x = w2;    pt.y = 0.0;    break;
															       case CP_SE:  pt.x = w2;    pt.y = -h2;    break;
																	        case CP_S:   pt.x = 0.0;   pt.y = -h1;    break;
																			         case CP_SW:  pt.x = -w2;   pt.y = -h2;    break;
																					          case CP_W:   pt.x = -w2;   pt.y = 0.0;    break;
																							           case CP_NW:  pt.x = -w2;   pt.y = h2;     break;
																										    default:     assert(0);
																												   }
		    UNUSED_PARAMETER(p);
		      return pt;
}

/* Methods for the "dot" class */
static void dotInit(Pik *p, PObj *pObj){
	  pObj->rad = pik_value(p, "dotrad",6,0);
	    pObj->h = pObj->w = pObj->rad*6;
	      pObj->fill = pObj->color;
}
static void dotNumProp(Pik *p, PObj *pObj, PToken *pId){
	  switch( pId->eType ){
		      case T_COLOR:
			            pObj->fill = pObj->color;
				          break;
					      case T_FILL:
					        pObj->color = pObj->fill;
						      break;
						        }
	    UNUSED_PARAMETER(p);
}
static void dotCheck(Pik *p, PObj *pObj){
	  pObj->w = pObj->h = 0;
	    pik_bbox_addellipse(&pObj->bbox, pObj->ptAt.x, pObj->ptAt.y,
			                           pObj->rad, pObj->rad);
	      UNUSED_PARAMETER(p);
}
static PPoint dotOffset(Pik *p, PObj *pObj, int cp){
	  UNUSED_PARAMETER(p);
	    UNUSED_PARAMETER(pObj);
	      UNUSED_PARAMETER(cp);
	        return cZeroPoint;
}
static void dotRender(Pik *p, PObj *pObj){
	  PNum r = pObj->rad;
	    PPoint pt = pObj->ptAt;
	      if( pObj->sw>0.0 ){
		          pik_append_x(p,"<circle cx=\"", pt.x, "\"");
			      pik_append_y(p," cy=\"", pt.y, "\"");
			          pik_append_dis(p," r=\"", r, "\"");
				      pik_append_style(p,pObj,1);
				          pik_append(p,"\" />\n", -1);
					    }
	        pik_append_txt(p, pObj, 0);
}



/* Methods for the "ellipse" class */
static void ellipseInit(Pik *p, PObj *pObj){
	  pObj->w = pik_value(p, "ellipsewid",10,0);
	    pObj->h = pik_value(p, "ellipseht",9,0);
}
static PPoint ellipseChop(Pik *p, PObj *pObj, PPoint *pPt){
	  PPoint chop;
	    PNum s, dq, dist;
	      PNum dx = pPt->x - pObj->ptAt.x;
	        PNum dy = pPt->y - pObj->ptAt.y;
		  if( pObj->w<=0.0 ) return pObj->ptAt;
		    if( pObj->h<=0.0 ) return pObj->ptAt;
		      s = pObj->h/pObj->w;
		        dq = dx*s;
			  dist = hypot(dq,dy);
			    if( dist<pObj->h ) return pObj->ptAt;
			      chop.x = pObj->ptAt.x + 0.5*dq*pObj->h/(dist*s);
			        chop.y = pObj->ptAt.y + 0.5*dy*pObj->h/dist;
				  UNUSED_PARAMETER(p);
				    return chop;
}
static PPoint ellipseOffset(Pik *p, PObj *pObj, int cp){
	  PPoint pt = cZeroPoint;
	    PNum w = pObj->w*0.5;
	      PNum w2 = w*0.70710678118654747608;
	        PNum h = pObj->h*0.5;
		  PNum h2 = h*0.70710678118654747608;
		    switch( cp ){
			        case CP_C:                                break;
									      case CP_N:   pt.x = 0.0;   pt.y = h;      break;
											       case CP_NE:  pt.x = w2;    pt.y = h2;     break;
													        case CP_E:   pt.x = w;     pt.y = 0.0;    break;
															         case CP_SE:  pt.x = w2;    pt.y = -h2;    break;
																	          case CP_S:   pt.x = 0.0;   pt.y = -h;     break;
																			           case CP_SW:  pt.x = -w2;   pt.y = -h2;    break;
																						    case CP_W:   pt.x = -w;    pt.y = 0.0;    break;
																								     case CP_NW:  pt.x = -w2;   pt.y = h2;     break;
																										      default:     assert(0);
																												     }
		      UNUSED_PARAMETER(p);
		        return pt;
}
static void ellipseRender(Pik *p, PObj *pObj){
	  PNum w = pObj->w;
	    PNum h = pObj->h;
	      PPoint pt = pObj->ptAt;
	        if( pObj->sw>0.0 ){
			    pik_append_x(p,"<ellipse cx=\"", pt.x, "\"");
			        pik_append_y(p," cy=\"", pt.y, "\"");
				    pik_append_dis(p," rx=\"", w/2.0, "\"");
				        pik_append_dis(p," ry=\"", h/2.0, "\" ");
					    pik_append_style(p,pObj,1);
					        pik_append(p,"\" />\n", -1);
						  }
		  pik_append_txt(p, pObj, 0);
}

/* Methods for the "file" object */
static void fileInit(Pik *p, PObj *pObj){
	  pObj->w = pik_value(p, "filewid",7,0);
	    pObj->h = pik_value(p, "fileht",6,0);
	      pObj->rad = pik_value(p, "filerad",7,0);
}
/* Return offset from the center of the file to the compass point 
 * ** given by parameter cp */
static PPoint fileOffset(Pik *p, PObj *pObj, int cp){
	  PPoint pt = cZeroPoint;
	    PNum w2 = 0.5*pObj->w;
	      PNum h2 = 0.5*pObj->h;
	        PNum rx = pObj->rad;
		  PNum mn = w2<h2 ? w2 : h2;
		    if( rx>mn ) rx = mn;
		      if( rx<mn*0.25 ) rx = mn*0.25;
		        pt.x = pt.y = 0.0;
			  rx *= 0.5;
			    switch( cp ){
				        case CP_C:                                   break;
										         case CP_N:   pt.x = 0.0;      pt.y = h2;     break;
												          case CP_NE:  pt.x = w2-rx;    pt.y = h2-rx;  break;
														           case CP_E:   pt.x = w2;       pt.y = 0.0;    break;
																	    case CP_SE:  pt.x = w2;       pt.y = -h2;    break;
																			     case CP_S:   pt.x = 0.0;      pt.y = -h2;    break;
																					      case CP_SW:  pt.x = -w2;      pt.y = -h2;    break;
																							       case CP_W:   pt.x = -w2;      pt.y = 0.0;    break;
																									        case CP_NW:  pt.x = -w2;      pt.y = h2;     break;
																											         default:     assert(0);
																													        }
			      UNUSED_PARAMETER(p);
			        return pt;
}
static void fileFit(Pik *p, PObj *pObj, PNum w, PNum h){
	  if( w>0 ) pObj->w = w;
	    if( h>0 ) pObj->h = h + 2*pObj->rad;
	      UNUSED_PARAMETER(p);
}
static void fileRender(Pik *p, PObj *pObj){
	  PNum w2 = 0.5*pObj->w;
	    PNum h2 = 0.5*pObj->h;
	      PNum rad = pObj->rad;
	        PPoint pt = pObj->ptAt;
		  PNum mn = w2<h2 ? w2 : h2;
		    if( rad>mn ) rad = mn;
		      if( rad<mn*0.25 ) rad = mn*0.25;
		        if( pObj->sw>0.0 ){
				    pik_append_xy(p,"<path d=\"M", pt.x-w2,pt.y-h2);
				        pik_append_xy(p,"L", pt.x+w2,pt.y-h2);
					    pik_append_xy(p,"L", pt.x+w2,pt.y+(h2-rad));
					        pik_append_xy(p,"L", pt.x+(w2-rad),pt.y+h2);
						    pik_append_xy(p,"L", pt.x-w2,pt.y+h2);
						        pik_append(p,"Z\" ",-1);
							    pik_append_style(p,pObj,1);
							        pik_append(p,"\" />\n",-1);
								    pik_append_xy(p,"<path d=\"M", pt.x+(w2-rad), pt.y+h2);
								        pik_append_xy(p,"L", pt.x+(w2-rad),pt.y+(h2-rad));
									    pik_append_xy(p,"L", pt.x+w2, pt.y+(h2-rad));
									        pik_append(p,"\" ",-1);
										    pik_append_style(p,pObj,0);
										        pik_append(p,"\" />\n",-1);
											  }
			  pik_append_txt(p, pObj, 0);
}


/* Methods for the "line" class */
static void lineInit(Pik *p, PObj *pObj){
	  pObj->w = pik_value(p, "linewid",7,0);
	    pObj->h = pik_value(p, "lineht",6,0);
	      pObj->rad = pik_value(p, "linerad",7,0);
	        pObj->fill = -1.0;
}
static PPoint lineOffset(Pik *p, PObj *pObj, int cp){
#if 0
	  /* In legacy PIC, the .center of an unclosed line is half way between
	   *   ** its .start and .end. */
	  if( cp==CP_C && !pObj->bClose ){
		      PPoint out;
		          out.x = 0.5*(pObj->ptEnter.x + pObj->ptExit.x) - pObj->ptAt.x;
			      out.y = 0.5*(pObj->ptEnter.x + pObj->ptExit.y) - pObj->ptAt.y;
			          return out;
				    }
#endif
	    return boxOffset(p,pObj,cp);
}
static void lineRender(Pik *p, PObj *pObj){
	  int i;
	    if( pObj->sw>0.0 ){
		        const char *z = "<path d=\"M";
			    int n = pObj->nPath;
			        if( pObj->larrow ){
					      pik_draw_arrowhead(p,&pObj->aPath[1],&pObj->aPath[0],pObj);
					          }
				    if( pObj->rarrow ){
					          pik_draw_arrowhead(p,&pObj->aPath[n-2],&pObj->aPath[n-1],pObj);
						      }
				        for(i=0; i<pObj->nPath; i++){
						      pik_append_xy(p,z,pObj->aPath[i].x,pObj->aPath[i].y);
						            z = "L";
							        }
					    if( pObj->bClose ){
						          pik_append(p,"Z",1);
							      }else{
								            pObj->fill = -1.0;
									        }
					        pik_append(p,"\" ",-1);
						    pik_append_style(p,pObj,pObj->bClose);
						        pik_append(p,"\" />\n", -1);
							  }
	      pik_append_txt(p, pObj, 0);
}

/* Methods for the "move" class */
static void moveInit(Pik *p, PObj *pObj){
	  pObj->w = pik_value(p, "movewid",7,0);
	    pObj->h = pObj->w;
	      pObj->fill = -1.0;
	        pObj->color = -1.0;
		  pObj->sw = -1.0;
}
static void moveRender(Pik *p, PObj *pObj){
	  /* No-op */
	  UNUSED_PARAMETER(p);
	    UNUSED_PARAMETER(pObj);
}

/* Methods for the "oval" class */
static void ovalInit(Pik *p, PObj *pObj){
	  pObj->h = pik_value(p, "ovalht",6,0);
	    pObj->w = pik_value(p, "ovalwid",7,0);
	      pObj->rad = 0.5*(pObj->h<pObj->w?pObj->h:pObj->w);
}
static void ovalNumProp(Pik *p, PObj *pObj, PToken *pId){
	  UNUSED_PARAMETER(p);
	    UNUSED_PARAMETER(pId);
	      /* Always adjust the radius to be half of the smaller of
	       *   ** the width and height. */
	      pObj->rad = 0.5*(pObj->h<pObj->w?pObj->h:pObj->w);
}
static void ovalFit(Pik *p, PObj *pObj, PNum w, PNum h){
	  UNUSED_PARAMETER(p);
	    if( w>0 ) pObj->w = w;
	      if( h>0 ) pObj->h = h;
	        if( pObj->w<pObj->h ) pObj->w = pObj->h;
		  pObj->rad = 0.5*(pObj->h<pObj->w?pObj->h:pObj->w);
}



/* Methods for the "spline" class */
static void splineInit(Pik *p, PObj *pObj){
	  pObj->w = pik_value(p, "linewid",7,0);
	    pObj->h = pik_value(p, "lineht",6,0);
	      pObj->rad = 1000;
	        pObj->fill = -1.0;  /* Disable fill by default */
}
/* Return a point along the path from "f" to "t" that is r units
 * ** prior to reaching "t", except if the path is less than 2*r total,
 * ** return the midpoint.
 * */
static PPoint radiusMidpoint(PPoint f, PPoint t, PNum r, int *pbMid){
	  PNum dx = t.x - f.x;
	    PNum dy = t.y - f.y;
	      PNum dist = hypot(dx,dy);
	        PPoint m;
		  if( dist<=0.0 ) return t;
		    dx /= dist;
		      dy /= dist;
		        if( r > 0.5*dist ){
				    r = 0.5*dist;
				        *pbMid = 1;
					  }else{
						      *pbMid = 0;
						        }
			  m.x = t.x - r*dx;
			    m.y = t.y - r*dy;
			      return m;
}
static void radiusPath(Pik *p, PObj *pObj, PNum r){
	  int i;
	    int n = pObj->nPath;
	      const PPoint *a = pObj->aPath;
	        PPoint m;
		  int isMid = 0;

		    pik_append_xy(p,"<path d=\"M", a[0].x, a[0].y);
		      m = radiusMidpoint(a[0], a[1], r, &isMid);
		        pik_append_xy(p," L ",m.x,m.y);
			  for(i=1; i<n-1; i++){
				      m = radiusMidpoint(a[i+1],a[i],r, &isMid);
				          pik_append_xy(p," Q ",a[i].x,a[i].y);
					      pik_append_xy(p," ",m.x,m.y);
					          if( !isMid ){
							        m = radiusMidpoint(a[i],a[i+1],r, &isMid);
								      pik_append_xy(p," L ",m.x,m.y);
								          }
						    }
			    pik_append_xy(p," L ",a[i].x,a[i].y);
			      pik_append(p,"\" ",-1);
			        pik_append_style(p,pObj,0);
				  pik_append(p,"\" />\n", -1);
}
static void splineRender(Pik *p, PObj *pObj){
	  if( pObj->sw>0.0 ){
		      int n = pObj->nPath;
		          PNum r = pObj->rad;
			      if( n<3 || r<=0.0 ){
				            lineRender(p,pObj);
					          return;
						      }
			          if( pObj->larrow ){
					        pik_draw_arrowhead(p,&pObj->aPath[1],&pObj->aPath[0],pObj);
						    }
				      if( pObj->rarrow ){
					            pik_draw_arrowhead(p,&pObj->aPath[n-2],&pObj->aPath[n-1],pObj);
						        }
				          radiusPath(p,pObj,pObj->rad);
					    }
	    pik_append_txt(p, pObj, 0);
}


/* Methods for the "text" class */
static void textInit(Pik *p, PObj *pObj){
	  pik_value(p, "textwid",7,0);
	    pik_value(p, "textht",6,0);
	      pObj->sw = 0.0;
}
static PPoint textOffset(Pik *p, PObj *pObj, int cp){
	  /* Automatically slim-down the width and height of text
	   *   ** statements so that the bounding box tightly encloses the text,
	   *     ** then get boxOffset() to do the offset computation.
	   *       */
	  pik_size_to_fit(p, &pObj->errTok,3);
	    return boxOffset(p, pObj, cp);
}

/* Methods for the "sublist" class */
static void sublistInit(Pik *p, PObj *pObj){
	  PList *pList = pObj->pSublist;
	    int i;
	      UNUSED_PARAMETER(p);
	        pik_bbox_init(&pObj->bbox);
		  for(i=0; i<pList->n; i++){
			      pik_bbox_addbox(&pObj->bbox, &pList->a[i]->bbox);
			        }
		    pObj->w = pObj->bbox.ne.x - pObj->bbox.sw.x;
		      pObj->h = pObj->bbox.ne.y - pObj->bbox.sw.y;
		        pObj->ptAt.x = 0.5*(pObj->bbox.ne.x + pObj->bbox.sw.x);
			  pObj->ptAt.y = 0.5*(pObj->bbox.ne.y + pObj->bbox.sw.y);
			    pObj->mCalc |= A_WIDTH|A_HEIGHT|A_RADIUS;
}


/*
 * ** The following array holds all the different kinds of objects.
 * ** The special [] object is separate.
 * */
static const PClass aClass[] = {
	   {  /* name */          "arc",
		         /* isline */        1,
			       /* eJust */         0,
			             /* xInit */         arcInit,
				           /* xNumProp */      0,
					         /* xCheck */        arcCheck,
						       /* xChop */         0,
						             /* xOffset */       boxOffset,
							           /* xFit */          0,
								         /* xRender */       arcRender
										    },
	      {  /* name */          "arrow",
		            /* isline */        1,
			          /* eJust */         0,
				        /* xInit */         arrowInit,
					      /* xNumProp */      0,
					            /* xCheck */        0,
						          /* xChop */         0,
							        /* xOffset */       lineOffset,
								      /* xFit */          0,
								            /* xRender */       splineRender 
										       },
	         {  /* name */          "box",
			       /* isline */        0,
			             /* eJust */         1,
				           /* xInit */         boxInit,
					         /* xNumProp */      0,
						       /* xCheck */        0,
						             /* xChop */         boxChop,
							           /* xOffset */       boxOffset,
								         /* xFit */          boxFit,
									       /* xRender */       boxRender 
										          },
		    {  /* name */          "circle",
			          /* isline */        0,
				        /* eJust */         0,
					      /* xInit */         circleInit,
					            /* xNumProp */      circleNumProp,
						          /* xCheck */        0,
							        /* xChop */         circleChop,
								      /* xOffset */       ellipseOffset,
								            /* xFit */          circleFit,
									          /* xRender */       circleRender 
											     },
		       {  /* name */          "cylinder",
			             /* isline */        0,
				           /* eJust */         1,
					         /* xInit */         cylinderInit,
						       /* xNumProp */      0,
						             /* xCheck */        0,
							           /* xChop */         boxChop,
								         /* xOffset */       cylinderOffset,
									       /* xFit */          cylinderFit,
									             /* xRender */       cylinderRender
											        },
		          {  /* name */          "dot",
				        /* isline */        0,
					      /* eJust */         0,
					            /* xInit */         dotInit,
						          /* xNumProp */      dotNumProp,
							        /* xCheck */        dotCheck,
								      /* xChop */         circleChop,
								            /* xOffset */       dotOffset,
									          /* xFit */          0,
										        /* xRender */       dotRender 
												   },
			     {  /* name */          "ellipse",
				           /* isline */        0,
					         /* eJust */         0,
						       /* xInit */         ellipseInit,
						             /* xNumProp */      0,
							           /* xCheck */        0,
								         /* xChop */         ellipseChop,
									       /* xOffset */       ellipseOffset,
									             /* xFit */          boxFit,
										           /* xRender */       ellipseRender
												      },
			        {  /* name */          "file",
					      /* isline */        0,
					            /* eJust */         1,
						          /* xInit */         fileInit,
							        /* xNumProp */      0,
								      /* xCheck */        0,
								            /* xChop */         boxChop,
									          /* xOffset */       fileOffset,
										        /* xFit */          fileFit,
											      /* xRender */       fileRender 
												         },
				   {  /* name */          "line",
					         /* isline */        1,
						       /* eJust */         0,
						             /* xInit */         lineInit,
							           /* xNumProp */      0,
								         /* xCheck */        0,
									       /* xChop */         0,
									             /* xOffset */       lineOffset,
										           /* xFit */          0,
											         /* xRender */       splineRender
													    },
				      {  /* name */          "move",
					            /* isline */        1,
						          /* eJust */         0,
							        /* xInit */         moveInit,
								      /* xNumProp */      0,
								            /* xCheck */        0,
									          /* xChop */         0,
										        /* xOffset */       boxOffset,
											      /* xFit */          0,
											            /* xRender */       moveRender
													       },
				         {  /* name */          "oval",
						       /* isline */        0,
						             /* eJust */         1,
							           /* xInit */         ovalInit,
								         /* xNumProp */      ovalNumProp,
									       /* xCheck */        0,
									             /* xChop */         boxChop,
										           /* xOffset */       boxOffset,
											         /* xFit */          ovalFit,
												       /* xRender */       boxRender
													          },
					    {  /* name */          "spline",
						          /* isline */        1,
							        /* eJust */         0,
								      /* xInit */         splineInit,
								            /* xNumProp */      0,
									          /* xCheck */        0,
										        /* xChop */         0,
											      /* xOffset */       lineOffset,
											            /* xFit */          0,
												          /* xRender */       splineRender
														     },
					       {  /* name */          "text",
						             /* isline */        0,
							           /* eJust */         0,
								         /* xInit */         textInit,
									       /* xNumProp */      0,
									             /* xCheck */        0,
										           /* xChop */         boxChop,
											         /* xOffset */       textOffset,
												       /* xFit */          boxFit,
												             /* xRender */       boxRender 
														        },
};
static const PClass sublistClass = 
   {  /* name */          "[]",
	         /* isline */        0,
		       /* eJust */         0,
		             /* xInit */         sublistInit,
			           /* xNumProp */      0,
				         /* xCheck */        0,
					       /* xChop */         0,
					             /* xOffset */       boxOffset,
						           /* xFit */          0,
							         /* xRender */       0 
									    };
static const PClass noopClass = 
   {  /* name */          "noop",
	         /* isline */        0,
		       /* eJust */         0,
		             /* xInit */         0,
			           /* xNumProp */      0,
				         /* xCheck */        0,
					       /* xChop */         0,
					             /* xOffset */       boxOffset,
						           /* xFit */          0,
							         /* xRender */       0
									    };


/*
 * ** Reduce the length of the line segment by amt (if possible) by
 * ** modifying the location of *t.
 * */
static void pik_chop(PPoint *f, PPoint *t, PNum amt){
	  PNum dx = t->x - f->x;
	    PNum dy = t->y - f->y;
	      PNum dist = hypot(dx,dy);
	        PNum r;
		  if( dist<=amt ){
			      *t = *f;
			          return;
				    }
		    r = 1.0 - amt/dist;
		      t->x = f->x + r*dx;
		        t->y = f->y + r*dy;
}

/*
 * ** Draw an arrowhead on the end of the line segment from pFrom to pTo.
 * ** Also, shorten the line segment (by changing the value of pTo) so that
 * ** the shaft of the arrow does not extend into the arrowhead.
 * */
static void pik_draw_arrowhead(Pik *p, PPoint *f, PPoint *t, PObj *pObj){
	  PNum dx = t->x - f->x;
	    PNum dy = t->y - f->y;
	      PNum dist = hypot(dx,dy);
	        PNum h = p->hArrow * pObj->sw;
		  PNum w = p->wArrow * pObj->sw;
		    PNum e1, ddx, ddy;
		      PNum bx, by;
		        if( pObj->color<0.0 ) return;
			  if( pObj->sw<=0.0 ) return;
			    if( dist<=0.0 ) return;  /* Unable */
			      dx /= dist;
			        dy /= dist;
				  e1 = dist - h;
				    if( e1<0.0 ){
					        e1 = 0.0;
						    h = dist;
						      }
				      ddx = -w*dy;
				        ddy = w*dx;
					  bx = f->x + e1*dx;
					    by = f->y + e1*dy;
					      pik_append_xy(p,"<polygon points=\"", t->x, t->y);
					        pik_append_xy(p," ",bx-ddx, by-ddy);
						  pik_append_xy(p," ",bx+ddx, by+ddy);
						    pik_append_clr(p,"\" style=\"fill:",pObj->color,"\"/>\n");
						      pik_chop(f,t,h/2);
}

/*
 * ** Compute the relative offset to an edge location from the reference for a
 * ** an statement.
 * */
static PPoint pik_elem_offset(Pik *p, PObj *pObj, int cp){
	  return pObj->type->xOffset(p, pObj, cp);
}


/*
 * ** Append raw text to zOut
 * */
static void pik_append(Pik *p, const char *zText, int n){
	  if( n<0 ) n = (int)strlen(zText);
	    if( p->nOut+n>=p->nOutAlloc ){
		        int nNew = (p->nOut+n)*2 + 1;
			    char *z = realloc(p->zOut, nNew);
			        if( z==0 ){
					      pik_error(p, 0, 0);
					            return;
						        }
				    p->zOut = z;
				        p->nOutAlloc = n;
					  }
	      memcpy(p->zOut+p->nOut, zText, n);
	        p->nOut += n;
		  p->zOut[p->nOut] = 0;
}

/*
 * ** Append text to zOut with HTML characters escaped.
 * **
 * **   *  The space character is changed into non-breaking space (U+00a0)
 * **      if mFlags has the 0x01 bit set. This is needed when outputting
 * **      text to preserve leading and trailing whitespace.  Turns out we
 * **      cannot use &nbsp; as that is an HTML-ism and is not valid in XML.
 * **
 * **   *  The "&" character is changed into "&amp;" if mFlags has the
 * **      0x02 bit set.  This is needed when generating error message text.
 * **
 * **   *  Except for the above, only "<" and ">" are escaped.
 * */
static void pik_append_text(Pik *p, const char *zText, int n, int mFlags){
	  int i;
	    char c;
	      int bQSpace = mFlags & 1;
	        int bQAmp = mFlags & 2;
		  if( n<0 ) n = (int)strlen(zText);
		    while( n>0 ){
			        for(i=0; i<n; i++){
					      c = zText[i];
					            if( c=='<' || c=='>' ) break;
						          if( c==' ' && bQSpace ) break;
							        if( c=='&' && bQAmp ) break;
								    }
				    if( i ) pik_append(p, zText, i);
				        if( i==n ) break;
					    switch( c ){
						          case '<': {  pik_append(p, "&lt;", 4);  break;  }
								          case '>': {  pik_append(p, "&gt;", 4);  break;  }
										          case '&': {  pik_append(p, "&amp;", 5);  break;  }
												          case ' ': {  pik_append(p, "\302\240;", 2);  break;  }
														        }
					        i++;
						    n -= i;
						        zText += i;
							    i = 0;
							      }
}

/* Append a PNum value
 * */
static void pik_append_num(Pik *p, const char *z,PNum v){
	  char buf[100];
	    snprintf(buf, sizeof(buf)-1, "%.10g", (double)v);
	      buf[sizeof(buf)-1] = 0;
	        pik_append(p, z, -1);
		  pik_append(p, buf, -1);
}

/* Append a PPoint value  (Used for debugging only)
 * */
static void pik_append_point(Pik *p, const char *z, PPoint *pPt){
	  char buf[100];
	    snprintf(buf, sizeof(buf)-1, "%.10g,%.10g", 
			              (double)pPt->x, (double)pPt->y);
	      buf[sizeof(buf)-1] = 0;
	        pik_append(p, z, -1);
		  pik_append(p, buf, -1);
}

/* Append a PNum value surrounded by text.  Do coordinate transformations
 * ** on the value.
 * */
static void pik_append_x(Pik *p, const char *z1, PNum v, const char *z2){
	  char buf[200];
	    v -= p->bbox.sw.x;
	      snprintf(buf, sizeof(buf)-1, "%s%d%s", z1, (int)(p->rScale*v), z2);
	        buf[sizeof(buf)-1] = 0;
		  pik_append(p, buf, -1);
}
static void pik_append_y(Pik *p, const char *z1, PNum v, const char *z2){
	  char buf[200];
	    v = p->bbox.ne.y - v;
	      snprintf(buf, sizeof(buf)-1, "%s%d%s", z1, (int)(p->rScale*v), z2);
	        buf[sizeof(buf)-1] = 0;
		  pik_append(p, buf, -1);
}
static void pik_append_xy(Pik *p, const char *z1, PNum x, PNum y){
	  char buf[200];
	    x = x - p->bbox.sw.x;
	      y = p->bbox.ne.y - y;
	        snprintf(buf, sizeof(buf)-1, "%s%d,%d", z1,
				       (int)(p->rScale*x), (int)(p->rScale*y));
		  buf[sizeof(buf)-1] = 0;
		    pik_append(p, buf, -1);
}
static void pik_append_dis(Pik *p, const char *z1, PNum v, const char *z2){
	  char buf[200];
	    snprintf(buf, sizeof(buf)-1, "%s%g%s", z1, p->rScale*v, z2);
	      buf[sizeof(buf)-1] = 0;
	        pik_append(p, buf, -1);
}
static void pik_append_clr(Pik *p, const char *z1, PNum v, const char *z2){
	  char buf[200];
	    int x = (int)v;
	      int r = (x>>16) & 0xff;
	        int g = (x>>8) & 0xff;
		  int b = x & 0xff;
		    snprintf(buf, sizeof(buf)-1, "%srgb(%d,%d,%d)%s", z1, r, g, b, z2);
		      buf[sizeof(buf)-1] = 0;
		        pik_append(p, buf, -1);
}

/* Append an SVG path A record:
 * **
 * **    A r1 r2 0 0 0 x y
 * */
static void pik_append_arc(Pik *p, PNum r1, PNum r2, PNum x, PNum y){
	  char buf[200];
	    x = x - p->bbox.sw.x;
	      y = p->bbox.ne.y - y;
	        snprintf(buf, sizeof(buf)-1, "A%d %d 0 0 0 %d %d", 
				     (int)(p->rScale*r1), (int)(p->rScale*r2),
				          (int)(p->rScale*x), (int)(p->rScale*y));
		  buf[sizeof(buf)-1] = 0;
		    pik_append(p, buf, -1);
}

/* Append a style="..." text.  But, leave the quote unterminated, in case
 * ** the caller wants to add some more.
 * */
static void pik_append_style(Pik *p, PObj *pObj, int bFill){
	  pik_append(p, " style=\"", -1);
	    if( pObj->fill>=0 && bFill ){
		        pik_append_clr(p, "fill:", pObj->fill, ";");
			  }else{
				      pik_append(p,"fill:none;",-1);
				        }
	      if( pObj->sw>0.0 && pObj->color>=0.0 ){
		          PNum sw = pObj->sw;
			      pik_append_dis(p, "stroke-width:", sw, ";");
			          if( pObj->nPath>2 && pObj->rad<=pObj->sw ){
					        pik_append(p, "stroke-linejoin:round;", -1);
						    }
				      pik_append_clr(p, "stroke:",pObj->color,";");
				          if( pObj->dotted>0.0 ){
						        PNum v = pObj->dotted;
							      if( sw<2.1/p->rScale ) sw = 2.1/p->rScale;
							            pik_append_dis(p,"stroke-dasharray:",sw,"");
								          pik_append_dis(p,",",v,";");
									      }else if( pObj->dashed>0.0 ){
										            PNum v = pObj->dashed;
											          pik_append_dis(p,"stroke-dasharray:",v,"");
												        pik_append_dis(p,",",v,";");
													    }
					    }
}

/*
 * ** Compute the vertical locations for all text items in the
 * ** object pObj.  In other words, set every pObj->aTxt[*].eCode
 * ** value to contain exactly one of: TP_ABOVE2, TP_ABOVE, TP_CENTER,
 * ** TP_BELOW, or TP_BELOW2 is set.
 * */
static void pik_txt_vertical_layout(PObj *pObj){
	  int n, i;
	    PToken *aTxt;
	      n = pObj->nTxt;
	        if( n==0 ) return;
		  aTxt = pObj->aTxt;
		    if( n==1 ){
			        if( (aTxt[0].eCode & TP_VMASK)==0 ){
					      aTxt[0].eCode |= TP_CENTER;
					          }
				  }else{
					      int allSlots = 0;
					          int aFree[5];
						      int iSlot;
						          int j, mJust;
							      /* If there is more than one TP_ABOVE, change the first to TP_ABOVE2. */
							      for(j=mJust=0, i=n-1; i>=0; i--){
								            if( aTxt[i].eCode & TP_ABOVE ){
										            if( j==0 ){
												              j++;
													                mJust = aTxt[i].eCode & TP_JMASK;
															        }else if( j==1 && mJust!=0 && (aTxt[i].eCode & mJust)==0 ){
																	          j++;
																		          }else{
																				            aTxt[i].eCode = (aTxt[i].eCode & ~TP_VMASK) | TP_ABOVE2;
																					              break;
																						              }
											          }
									        }
							          /* If there is more than one TP_BELOW, change the last to TP_BELOW2 */
							          for(j=mJust=0, i=0; i<n; i++){
									        if( aTxt[i].eCode & TP_BELOW ){
											        if( j==0 ){
													          j++;
														            mJust = aTxt[i].eCode & TP_JMASK;
															            }else if( j==1 && mJust!=0 && (aTxt[i].eCode & mJust)==0 ){
																	              j++;
																		              }else{
																				                aTxt[i].eCode = (aTxt[i].eCode & ~TP_VMASK) | TP_BELOW2;
																						          break;
																							          }
												      }
										    }
								      /* Compute a mask of all slots used */
								      for(i=0; i<n; i++) allSlots |= aTxt[i].eCode & TP_VMASK;
								          /* Set of an array of available slots */
								          if( n==2
											       && ((aTxt[0].eCode|aTxt[1].eCode)&TP_JMASK)==(TP_LJUST|TP_RJUST)
											           ){
										        /* Special case of two texts that have opposite justification:
											 *       ** Allow them both to float to center. */
										        iSlot = 2;
											      aFree[0] = aFree[1] = TP_CENTER;
											          }else{
													        /* Set up the arrow so that available slots are filled from top to
														 *       ** bottom */
													        iSlot = 0;
														      if( n>=4 && (allSlots & TP_ABOVE2)==0 ) aFree[iSlot++] = TP_ABOVE2;
														            if( (allSlots & TP_ABOVE)==0 ) aFree[iSlot++] = TP_ABOVE;
															          if( (n&1)!=0 ) aFree[iSlot++] = TP_CENTER;
																        if( (allSlots & TP_BELOW)==0 ) aFree[iSlot++] = TP_BELOW;
																	      if( n>=4 && (allSlots & TP_BELOW2)==0 ) aFree[iSlot++] = TP_BELOW2;
																	          }
									      /* Set the VMASK for all unassigned texts */
									      for(i=iSlot=0; i<n; i++){
										            if( (aTxt[i].eCode & TP_VMASK)==0 ){
												            aTxt[i].eCode |= aFree[iSlot++];
													          }
											        }
									        }
}

/* Append multiple <text> SVG elements for the text fields of the PObj.
 * ** Parameters:
 * **
 * **    p          The Pik object into which we are rendering
 * **
 * **    pObj      Object containing the text to be rendered
 * **
 * **    pBox       If not NULL, do no rendering at all.  Instead
 * **               expand the box object so that it will include all
 * **               of the text.
 * */
static void pik_append_txt(Pik *p, PObj *pObj, PBox *pBox){
	  PNum dy;          /* Half the height of a single line of text */
	    PNum dy2;         /* Extra vertical space around the center */
	      PNum jw;          /* Justification margin relative to center */
	        int n, i, nz;
		  PNum x, y, orig_y;
		    const char *z;
		      PToken *aTxt;
		        int hasCenter = 0;

			  if( p->nErr ) return;
			    if( pObj->nTxt==0 ) return;
			      aTxt = pObj->aTxt;
			        dy = 0.5*p->charHeight;
				  n = pObj->nTxt;
				    pik_txt_vertical_layout(pObj);
				      x = pObj->ptAt.x;
				        for(i=0; i<n; i++){
						    if( (pObj->aTxt[i].eCode & TP_CENTER)!=0 ) hasCenter = 1;
						      }
					  if( hasCenter ){
						      dy2 = dy;
						        }else if( pObj->type->isLine ){
								    dy2 = pObj->sw;
								      }else{
									          dy2 = 0.0;
										    }
					    if( pObj->type->eJust==1 ){
						        jw = 0.5*(pObj->w - 0.5*(p->charWidth + pObj->sw));
							  }else{
								      jw = 0.0;
								        }
					      for(i=0; i<n; i++){
						          PToken *t = &aTxt[i];
							      PNum xtraFontScale = 1.0;
							          orig_y = pObj->ptAt.y;
								      PNum nx = 0;
								          y = 0;
									      if( t->eCode & TP_ABOVE2 ) y += dy2 + 3*dy;
									          if( t->eCode & TP_ABOVE  ) y += dy2 + dy;
										      if( t->eCode & TP_BELOW  ) y -= dy2 + dy;
										          if( t->eCode & TP_BELOW2 ) y -= dy2 + 3*dy;
											      if( t->eCode & TP_BIG    ) xtraFontScale *= 1.25;
											          if( t->eCode & TP_SMALL  ) xtraFontScale *= 0.8;
												      if( t->eCode & TP_XTRA   ) xtraFontScale *= xtraFontScale;
												          if( t->eCode & TP_LJUST  ) nx -= jw;
													      if( t->eCode & TP_RJUST  ) nx += jw;

													          if( pBox!=0 ){
															        /* If pBox is not NULL, do not draw any <text>.  Instead, just expand
																 *       ** pBox to include the text */
															        PNum cw = pik_text_length(t)*p->charWidth*xtraFontScale*0.01;
																      PNum ch = p->charHeight*0.5*xtraFontScale;
																            PNum x0, y0, x1, y1;  /* Boundary of text relative to pObj->ptAt */
																	          if( t->eCode & TP_BOLD ) cw *= 1.1;
																		        if( t->eCode & TP_RJUST ){
																				        x0 = nx;
																					        y0 = y-ch;
																						        x1 = nx-cw;
																							        y1 = y+ch;
																								      }else if( t->eCode & TP_LJUST ){
																									              x0 = nx;
																										              y0 = y-ch;
																											              x1 = nx+cw;
																												              y1 = y+ch;
																													            }else{
																															            x0 = nx+cw/2;
																																            y0 = y+ch;
																																	            x1 = nx-cw/2;
																																		            y1 = y-ch;
																																			          }
																			      if( (t->eCode & TP_ALIGN)!=0 && pObj->nPath>=2 ){
																				              int n = pObj->nPath;
																					              PNum dx = pObj->aPath[n-1].x - pObj->aPath[0].x;
																						              PNum dy = pObj->aPath[n-1].y - pObj->aPath[0].y;
																							              if( dx!=0 || dy!=0 ){
																									                PNum dist = hypot(dx,dy);
																											          PNum t;
																												            dx /= dist;
																													              dy /= dist;
																														                t = dx*x0 - dy*y0;
																																          y0 = dy*x0 - dx*y0;
																																	            x0 = t;
																																		              t = dx*x1 - dy*y1;
																																			                y1 = dy*x1 - dx*y1;
																																					          x1 = t;
																																						          }
																								            }
																			            pik_bbox_add_xy(pBox, x+x0, orig_y+y0);
																				          pik_bbox_add_xy(pBox, x+x1, orig_y+y1);
																					        continue;
																						    }
														      nx += x;
														          y += orig_y;

															      pik_append_x(p, "<text x=\"", nx, "\"");
															          pik_append_y(p, " y=\"", y, "\"");
																      if( t->eCode & TP_RJUST ){
																	            pik_append(p, " text-anchor=\"end\"", -1);
																		        }else if( t->eCode & TP_LJUST ){
																				      pik_append(p, " text-anchor=\"start\"", -1);
																				          }else{
																						        pik_append(p, " text-anchor=\"middle\"", -1);
																							    }
																          if( t->eCode & TP_ITALIC ){
																		        pik_append(p, " font-style=\"italic\"", -1);
																			    }
																	      if( t->eCode & TP_BOLD ){
																		            pik_append(p, " font-weight=\"bold\"", -1);
																			        }
																	          if( pObj->color>=0.0 ){
																			        pik_append_clr(p, " fill=\"", pObj->color, "\"");
																				    }
																		      xtraFontScale *= p->fontScale;
																		          if( xtraFontScale<=0.99 || xtraFontScale>=1.01 ){
																				        pik_append_num(p, " font-size=\"", xtraFontScale*100.0);
																					      pik_append(p, "%\"", 2);
																					          }
																			      if( (t->eCode & TP_ALIGN)!=0 && pObj->nPath>=2 ){
																				            int n = pObj->nPath;
																					          PNum dx = pObj->aPath[n-1].x - pObj->aPath[0].x;
																						        PNum dy = pObj->aPath[n-1].y - pObj->aPath[0].y;
																							      if( dx!=0 || dy!=0 ){
																								              PNum ang = atan2(dy,dx)*-180/M_PI;
																									              pik_append_num(p, " transform=\"rotate(", ang);
																										              pik_append_xy(p, " ", x, orig_y);
																											              pik_append(p,")\"",2);
																												            }
																							          }
																			          pik_append(p," dominant-baseline=\"central\">",-1);
																				      if( t->n>=2 && t->z[0]=='"' ){
																					            z = t->z+1;
																						          nz = t->n-2;
																							      }else{
																								            z = t->z;
																									          nz = t->n;
																										      }
																				          while( nz>0 ){
																						        int j;
																							      for(j=0; j<nz && z[j]!='\\'; j++){}
																							            if( j ) pik_append_text(p, z, j, 1);
																								          nz -= j+1;
																									        z += j+1;
																										    }
																					      pik_append(p, "</text>\n", -1);
																					        }
}

/*
 * ** Append text (that will go inside of a <pre>...</pre>) that
 * ** shows the context of an error token.
 * */
static void pik_error_context(Pik *p, PToken *pErr, int nContext){
	  int iErrPt;           /* Index of first byte of error from start of input */
	    int iErrCol;          /* Column of the error token on its line */
	      int iStart;           /* Start position of the error context */
	        int iEnd;             /* End position of the error context */
		  int iLineno;          /* Line number of the error */
		    int iFirstLineno;     /* Line number of start of error context */
		      int i;                /* Loop counter */
		        char zLineno[20];     /* Buffer in which to generate line numbers */

			  iErrPt = (int)(pErr->z - p->sIn.z);
			    iLineno = 1;
			      for(i=0; i<iErrPt; i++){
				          if( p->sIn.z[i]=='\n' ){
						        iLineno++;
							    }
					    }
			        iStart = 0;
				  iFirstLineno = 1;
				    while( iFirstLineno+nContext<iLineno ){
					        while( p->sIn.z[iStart]!='\n' ){ iStart++; }
						    iStart++;
						        iFirstLineno++;
							  }
				      for(iEnd=iErrPt; p->sIn.z[iEnd]!=0 && p->sIn.z[iEnd]!='\n'; iEnd++){}
				        i = iStart;
					  while( iFirstLineno<=iLineno ){
						      snprintf(zLineno,sizeof(zLineno)-1,"/* %4d */  ", iFirstLineno++);
						          zLineno[sizeof(zLineno)-1] = 0;
							      pik_append(p, zLineno, -1);
							          for(i=iStart; p->sIn.z[i]!=0 && p->sIn.z[i]!='\n'; i++){}
								      pik_append_text(p, p->sIn.z+iStart, i-iStart, 0);
								          iStart = i+1;
									      pik_append(p, "\n", 1);
									        }
					    for(iErrCol=0, i=iErrPt; i>0 && p->sIn.z[i]!='\n'; iErrCol++, i--){}
					      for(i=0; i<iErrCol+11; i++){ pik_append(p, " ", 1); }
					        for(i=0; i<(int)pErr->n; i++) pik_append(p, "^", 1);
						  pik_append(p, "\n", 1);
}


/*
 * ** Generate an error message for the output.  pErr is the token at which
 * ** the error should point.  zMsg is the text of the error message. If
 * ** either pErr or zMsg is NULL, generate an out-of-memory error message.
 * **
 * ** This routine is a no-op if there has already been an error reported.
 * */
static void pik_error(Pik *p, PToken *pErr, const char *zMsg){
	  int i;
	    if( p==0 ) return;
	      if( p->nErr ) return;
	        p->nErr++;
		  if( zMsg==0 ){
			      pik_append(p, "\n<div><p>Out of memory</p></div>\n", -1);
			          return;
				    }
		    if( pErr==0 ){
			        pik_append(p, "\n", 1);
				    pik_append_text(p, zMsg, -1, 0);
				        return;
					  }
		      pik_append(p, "<div><pre>\n", -1);
		        pik_error_context(p, pErr, 5);
			  pik_append(p, "ERROR: ", -1);
			    pik_append_text(p, zMsg, -1, 0);
			      pik_append(p, "\n", 1);
			        for(i=p->nCtx-1; i>=0; i--){
					    pik_append(p, "Called from:\n", -1);
					        pik_error_context(p, &p->aCtx[i], 0);
						  }
				  pik_append(p, "</pre></div>\n", -1);
}

/*
 * ** Process an "assert( e1 == e2 )" statement.  Always return NULL.
 * */
static PObj *pik_assert(Pik *p, PNum e1, PToken *pEq, PNum e2){
	  char zE1[100], zE2[100], zMsg[300];

	    /* Convert the numbers to strings using %g for comparison.  This
	     *   ** limits the precision of the comparison to account for rounding error. */
	    snprintf(zE1, sizeof(zE1), "%g", e1); zE1[sizeof(zE1)-1] = 0;
	      snprintf(zE2, sizeof(zE2), "%g", e2); zE1[sizeof(zE2)-1] = 0;
	        if( strcmp(zE1,zE2)!=0 ){
			    snprintf(zMsg, sizeof(zMsg), "%.50s != %.50s", zE1, zE2);
			        pik_error(p, pEq, zMsg);
				  }
		  return 0;
}

/*
 * ** Process an "assert( place1 == place2 )" statement.  Always return NULL.
 * */
static PObj *pik_position_assert(Pik *p, PPoint *e1, PToken *pEq, PPoint *e2){
	  char zE1[100], zE2[100], zMsg[210];

	    /* Convert the numbers to strings using %g for comparison.  This
	     *   ** limits the precision of the comparison to account for rounding error. */
	    snprintf(zE1, sizeof(zE1), "(%g,%g)", e1->x, e1->y); zE1[sizeof(zE1)-1] = 0;
	      snprintf(zE2, sizeof(zE2), "(%g,%g)", e2->x, e2->y); zE1[sizeof(zE2)-1] = 0;
	        if( strcmp(zE1,zE2)!=0 ){
			    snprintf(zMsg, sizeof(zMsg), "%s != %s", zE1, zE2);
			        pik_error(p, pEq, zMsg);
				  }
		  return 0;
}

/* Free a complete list of objects */
static void pik_elist_free(Pik *p, PList *pList){
	  int i;
	    if( pList==0 ) return;
	      for(i=0; i<pList->n; i++){
		          pik_elem_free(p, pList->a[i]);
			    }
	        free(pList->a);
		  free(pList);
		    return;
}

/* Free a single object, and its substructure */
static void pik_elem_free(Pik *p, PObj *pObj){
	  if( pObj==0 ) return;
	    free(pObj->zName);
	      pik_elist_free(p, pObj->pSublist);
	        free(pObj->aPath);
		  free(pObj);
}

/* Convert a numeric literal into a number.  Return that number.
 * ** There is no error handling because the tokenizer has already
 * ** assured us that the numeric literal is valid.
 * **
 * ** Allowed number forms:
 * **
 * **   (1)    Floating point literal
 * **   (2)    Same as (1) but followed by a unit: "cm", "mm", "in",
 * **          "px", "pt", or "pc".
 * **   (3)    Hex integers: 0x000000
 * **
 * ** This routine returns the result in inches.  If a different unit
 * ** is specified, the conversion happens automatically.
 * */
PNum pik_atof(PToken *num){
	  char *endptr;
	    PNum ans;
	      if( num->n>=3 && num->z[0]=='0' && (num->z[1]=='x'||num->z[1]=='X') ){
		          return (PNum)strtol(num->z+2, 0, 16);
			    }
	        ans = strtod(num->z, &endptr);
		  if( (int)(endptr - num->z)==(int)num->n-2 ){
			      char c1 = endptr[0];
			          char c2 = endptr[1];
				      if( c1=='c' && c2=='m' ){
					            ans /= 2.54;
						        }else if( c1=='m' && c2=='m' ){
								      ans /= 25.4;
								          }else if( c1=='p' && c2=='x' ){
										        ans /= 96;
											    }else if( c1=='p' && c2=='t' ){
												          ans /= 72;
													      }else if( c1=='p' && c2=='c' ){
														            ans /= 6;
															        }
				        }
		    return ans;
}

/*
 * ** Compute the distance between two points
 * */
static PNum pik_dist(PPoint *pA, PPoint *pB){
	  PNum dx, dy;
	    dx = pB->x - pA->x;
	      dy = pB->y - pA->y;
	        return hypot(dx,dy);
}

/* Return true if a bounding box is empty.
 * */
static int pik_bbox_isempty(PBox *p){
	  return p->sw.x>p->ne.x;
}

/* Initialize a bounding box to an empty container
 * */
static void pik_bbox_init(PBox *p){
	  p->sw.x = 1.0;
	    p->sw.y = 1.0;
	      p->ne.x = 0.0;
	        p->ne.y = 0.0;
}

/* Enlarge the PBox of the first argument so that it fully
 * ** covers the second PBox
 * */
static void pik_bbox_addbox(PBox *pA, PBox *pB){
	  if( pik_bbox_isempty(pA) ){
		      *pA = *pB;
		        }
	    if( pik_bbox_isempty(pB) ) return;
	      if( pA->sw.x>pB->sw.x ) pA->sw.x = pB->sw.x;
	        if( pA->sw.y>pB->sw.y ) pA->sw.y = pB->sw.y;
		  if( pA->ne.x<pB->ne.x ) pA->ne.x = pB->ne.x;
		    if( pA->ne.y<pB->ne.y ) pA->ne.y = pB->ne.y;
}

/* Enlarge the PBox of the first argument, if necessary, so that
 * ** it contains the point described by the 2nd and 3rd arguments.
 * */
static void pik_bbox_add_xy(PBox *pA, PNum x, PNum y){
	  if( pik_bbox_isempty(pA) ){
		      pA->ne.x = x;
		          pA->ne.y = y;
			      pA->sw.x = x;
			          pA->sw.y = y;
				      return;
				        }
	    if( pA->sw.x>x ) pA->sw.x = x;
	      if( pA->sw.y>y ) pA->sw.y = y;
	        if( pA->ne.x<x ) pA->ne.x = x;
		  if( pA->ne.y<y ) pA->ne.y = y;
}

/* Enlarge the PBox so that it is able to contain an ellipse
 * ** centered at x,y and with radiuses rx and ry.
 * */
static void pik_bbox_addellipse(PBox *pA, PNum x, PNum y, PNum rx, PNum ry){
	  if( pik_bbox_isempty(pA) ){
		      pA->ne.x = x+rx;
		          pA->ne.y = y+ry;
			      pA->sw.x = x-rx;
			          pA->sw.y = y-ry;
				      return;
				        }
	    if( pA->sw.x>x-rx ) pA->sw.x = x-rx;
	      if( pA->sw.y>y-ry ) pA->sw.y = y-ry;
	        if( pA->ne.x<x+rx ) pA->ne.x = x+rx;
		  if( pA->ne.y<y+ry ) pA->ne.y = y+ry;
}



/* Append a new object onto the end of an object list.  The
 * ** object list is created if it does not already exist.  Return
 * ** the new object list.
 * */
static PList *pik_elist_append(Pik *p, PList *pList, PObj *pObj){
	  if( pObj==0 ) return pList;
	    if( pList==0 ){
		        pList = malloc(sizeof(*pList));
			    if( pList==0 ){
				          pik_error(p, 0, 0);
					        pik_elem_free(p, pObj);
						      return 0;
						          }
			        memset(pList, 0, sizeof(*pList));
				  }
	      if( pList->n>=pList->nAlloc ){
		          int nNew = (pList->n+5)*2;
			      PObj **pNew = realloc(pList->a, sizeof(PObj*)*nNew);
			          if( pNew==0 ){
					        pik_error(p, 0, 0);
						      pik_elem_free(p, pObj);
						            return pList;
							        }
				      pList->nAlloc = nNew;
				          pList->a = pNew;
					    }
	        pList->a[pList->n++] = pObj;
		  p->list = pList;
		    return pList;
}

/* Convert an object class name into a PClass pointer
 * */
static const PClass *pik_find_class(PToken *pId){
	  int first = 0;
	    int last = count(aClass) - 1;
	      do{
		          int mid = (first+last)/2;
			      int c = strncmp(aClass[mid].zName, pId->z, pId->n);
			          if( c==0 ){
					        c = aClass[mid].zName[pId->n]!=0;
						      if( c==0 ) return &aClass[mid];
						          }
				      if( c<0 ){
					            first = mid + 1;
						        }else{
								      last = mid - 1;
								          }
				        }while( first<=last );
	        return 0;
}

/* Allocate and return a new PObj object.
 * **
 * ** If pId!=0 then pId is an identifier that defines the object class.
 * ** If pStr!=0 then it is a STRING literal that defines a text object.
 * ** If pSublist!=0 then this is a [...] object. If all three parameters
 * ** are NULL then this is a no-op object used to define a PLACENAME.
 * */
static PObj *pik_elem_new(Pik *p, PToken *pId, PToken *pStr,PList *pSublist){
	  PObj *pNew;
	    int miss = 0;

	      if( p->nErr ) return 0;
	        pNew = malloc( sizeof(*pNew) );
		  if( pNew==0 ){
			      pik_error(p,0,0);
			          pik_elist_free(p, pSublist);
				      return 0;
				        }
		    memset(pNew, 0, sizeof(*pNew));
		      p->cur = pNew;
		        p->nTPath = 1;
			  p->thenFlag = 0;
			    if( p->list==0 || p->list->n==0 ){
				        pNew->ptAt.x = pNew->ptAt.y = 0.0;
					    pNew->eWith = CP_C;
					      }else{
						          PObj *pPrior = p->list->a[p->list->n-1];
							      pNew->ptAt = pPrior->ptExit;
							          switch( p->eDir ){
									        default:         pNew->eWith = CP_W;   break;
												       case DIR_LEFT:   pNew->eWith = CP_E;   break;
															      case DIR_UP:     pNew->eWith = CP_S;   break;
																	             case DIR_DOWN:   pNew->eWith = CP_N;   break;
																				          }
								    }
			      p->aTPath[0] = pNew->ptAt;
			        pNew->with = pNew->ptAt;
				  pNew->outDir = pNew->inDir = p->eDir;
				    pNew->iLayer = (int)pik_value(p, "layer", 5, &miss);
				      if( miss ) pNew->iLayer = 1000;
				        if( pNew->iLayer<0 ) pNew->iLayer = 0;
					  if( pSublist ){
						      pNew->type = &sublistClass;
						          pNew->pSublist = pSublist;
							      sublistClass.xInit(p,pNew);
							          return pNew;
								    }
					    if( pStr ){
						        PToken n;
							    n.z = "text";
							        n.n = 4;
								    pNew->type = pik_find_class(&n);
								        assert( pNew->type!=0 );
									    pNew->errTok = *pStr;
									        pNew->type->xInit(p, pNew);
										    pik_add_txt(p, pStr, pStr->eCode);
										        return pNew;
											  }
					      if( pId ){
						          pNew->errTok = *pId;
							      const PClass *pClass = pik_find_class(pId);
							          if( pClass ){
									        pNew->type = pClass;
										      pNew->sw = pik_value(p, "thickness",9,0);
										            pNew->fill = pik_value(p, "fill",4,0);
											          pNew->color = pik_value(p, "color",5,0);
												        pClass->xInit(p, pNew);
													      return pNew;
													          }
								      pik_error(p, pId, "unknown object type");
								          pik_elem_free(p, pNew);
									      return 0;
									        }
					        pNew->type = &noopClass;
						  pNew->ptExit = pNew->ptEnter = pNew->ptAt;
						    return pNew;
}

/*
 * ** If the ID token in the argument is the name of a macro, return
 * ** the PMacro object for that macro
 * */
static PMacro *pik_find_macro(Pik *p, PToken *pId){
	  PMacro *pMac;
	    for(pMac = p->pMacros; pMac; pMac=pMac->pNext){
		        if( pMac->macroName.n==pId->n
					     && strncmp(pMac->macroName.z,pId->z,pId->n)==0
					         ){
				      return pMac;
				          }
			  }
	      return 0;
}

/* Add a new macro
 * */
static void pik_add_macro(
		  Pik *p,          /* Current Pikchr diagram */
		    PToken *pId,     /* The ID token that defines the macro name */
		      PToken *pCode    /* Macro body inside of {...} */
		){
	  PMacro *pNew = pik_find_macro(p, pId);
	    if( pNew==0 ){
		        pNew = malloc( sizeof(*pNew) );
			    if( pNew==0 ){
				          pik_error(p, 0, 0);
					        return;
						    }
			        pNew->pNext = p->pMacros;
				    p->pMacros = pNew;
				        pNew->macroName = *pId;
					  }
	      pNew->macroBody.z = pCode->z+1;
	        pNew->macroBody.n = pCode->n-2;
		  pNew->inUse = 0;
}


/*
 * ** Set the output direction and exit point for an object
 * */
static void pik_elem_set_exit(PObj *pObj, int eDir){
	  assert( ValidDir(eDir) );
	    pObj->outDir = eDir;
	      if( !pObj->type->isLine || pObj->bClose ){
		          pObj->ptExit = pObj->ptAt;
			      switch( pObj->outDir ){
				            default:         pObj->ptExit.x += pObj->w*0.5;  break;
							           case DIR_LEFT:   pObj->ptExit.x -= pObj->w*0.5;  break;
										          case DIR_UP:     pObj->ptExit.y += pObj->h*0.5;  break;
													         case DIR_DOWN:   pObj->ptExit.y -= pObj->h*0.5;  break;
																      }
			        }
}

/* Change the layout direction.
 * */
static void pik_set_direction(Pik *p, int eDir){
	  assert( ValidDir(eDir) );
	    p->eDir = eDir;

	      /* It seems to make sense to reach back into the last object and
	       *   ** change its exit point (its ".end") to correspond to the new
	       *     ** direction.  Things just seem to work better this way.  However,
	       *       ** legacy PIC does *not* do this.
	       *         **
	       *           ** The difference can be seen in a script like this:
	       *             **
	       *               **      arrow; circle; down; arrow
	       *                 **
	       *                   ** You can make pikchr render the above exactly like PIC
	       *                     ** by deleting the following three lines.  But I (drh) think
	       *                       ** it works better with those lines in place.
	       *                         */
	      if( p->list && p->list->n ){
		          pik_elem_set_exit(p->list->a[p->list->n-1], eDir);
			    }
}

/* Move all coordinates contained within an object (and within its
 * ** substructure) by dx, dy
 * */
static void pik_elem_move(PObj *pObj, PNum dx, PNum dy){
	  int i;
	    pObj->ptAt.x += dx;
	      pObj->ptAt.y += dy;
	        pObj->ptEnter.x += dx;
		  pObj->ptEnter.y += dy;
		    pObj->ptExit.x += dx;
		      pObj->ptExit.y += dy;
		        pObj->bbox.ne.x += dx;
			  pObj->bbox.ne.y += dy;
			    pObj->bbox.sw.x += dx;
			      pObj->bbox.sw.y += dy;
			        for(i=0; i<pObj->nPath; i++){
					    pObj->aPath[i].x += dx;
					        pObj->aPath[i].y += dy;
						  }
				  if( pObj->pSublist ){
					      pik_elist_move(pObj->pSublist, dx, dy);
					        }
}
static void pik_elist_move(PList *pList, PNum dx, PNum dy){
	  int i;
	    for(i=0; i<pList->n; i++){
		        pik_elem_move(pList->a[i], dx, dy);
			  }
}

/*
 * ** Check to see if it is ok to set the value of paraemeter mThis.
 * ** Return 0 if it is ok. If it not ok, generate an appropriate
 * ** error message and return non-zero.
 * **
 * ** Flags are set in pObj so that the same object or conflicting
 * ** objects may not be set again.
 * **
 * ** To be ok, bit mThis must be clear and no more than one of
 * ** the bits identified by mBlockers may be set.
 * */
static int pik_param_ok(
		  Pik *p,             /* For storing the error message (if any) */
		    PObj *pObj,       /* The object under construction */
		      PToken *pId,        /* Make the error point to this token */
		        int mThis           /* Value we are trying to set */
		){
	  if( pObj->mProp & mThis ){
		      pik_error(p, pId, "value is already set");
		          return 1;
			    }
	    if( pObj->mCalc & mThis ){
		        pik_error(p, pId, "value already fixed by prior constraints");
			    return 1;
			      }
	      pObj->mProp |= mThis;
	        return 0;
}


/*
 * ** Set a numeric property like "width 7" or "radius 200%".
 * **
 * ** The rAbs term is an absolute value to add in.  rRel is
 * ** a relative value by which to change the current value.
 * */
void pik_set_numprop(Pik *p, PToken *pId, PRel *pVal){
	  PObj *pObj = p->cur;
	    switch( pId->eType ){
		        case T_HEIGHT:
				      if( pik_param_ok(p, pObj, pId, A_HEIGHT) ) return;
				            pObj->h = pObj->h*pVal->rRel + pVal->rAbs;
					          break;
						      case T_WIDTH:
						        if( pik_param_ok(p, pObj, pId, A_WIDTH) ) return;
							      pObj->w = pObj->w*pVal->rRel + pVal->rAbs;
							            break;
								        case T_RADIUS:
								          if( pik_param_ok(p, pObj, pId, A_RADIUS) ) return;
									        pObj->rad = pObj->rad*pVal->rRel + pVal->rAbs;
										      break;
										          case T_DIAMETER:
										            if( pik_param_ok(p, pObj, pId, A_RADIUS) ) return;
											          pObj->rad = pObj->rad*pVal->rRel + 0.5*pVal->rAbs; /* diam it 2x rad */
												        break;
													    case T_THICKNESS:
													      if( pik_param_ok(p, pObj, pId, A_THICKNESS) ) return;
													            pObj->sw = pObj->sw*pVal->rRel + pVal->rAbs;
														          break;
															    }
	      if( pObj->type->xNumProp ){
		          pObj->type->xNumProp(p, pObj, pId);
			    }
	        return;
}

/*
 * ** Set a color property.  The argument is an RGB value.
 * */
void pik_set_clrprop(Pik *p, PToken *pId, PNum rClr){
	  PObj *pObj = p->cur;
	    switch( pId->eType ){
		        case T_FILL:
				      if( pik_param_ok(p, pObj, pId, A_FILL) ) return;
				            pObj->fill = rClr;
					          break;
						      case T_COLOR:
						        if( pik_param_ok(p, pObj, pId, A_COLOR) ) return;
							      pObj->color = rClr;
							            break;
								      }
	      if( pObj->type->xNumProp ){
		          pObj->type->xNumProp(p, pObj, pId);
			    }
	        return;
}

/*
 * ** Set a "dashed" property like "dash 0.05"
 * **
 * ** Use the value supplied by pVal if available.  If pVal==0, use
 * ** a default.
 * */
void pik_set_dashed(Pik *p, PToken *pId, PNum *pVal){
	  PObj *pObj = p->cur;
	    PNum v;
	      switch( pId->eType ){
		          case T_DOTTED:  {
						        v = pVal==0 ? pik_value(p,"dashwid",7,0) : *pVal;
							      pObj->dotted = v;
							            pObj->dashed = 0.0;
								          break;
									      }
					      case T_DASHED:  {
								            v = pVal==0 ? pik_value(p,"dashwid",7,0) : *pVal;
									          pObj->dashed = v;
										        pObj->dotted = 0.0;
											      break;
											          }
							        }
}

/*
 * ** If the current path information came from a "same" or "same as"
 * ** reset it.
 * */
static void pik_reset_samepath(Pik *p){
	  if( p->samePath ){
		      p->samePath = 0;
		          p->nTPath = 1;
			    }
}


/* Add a new term to the path for a line-oriented object by transferring
 * ** the information in the ptTo field over onto the path and into ptFrom
 * ** resetting the ptTo.
 * */
static void pik_then(Pik *p, PToken *pToken, PObj *pObj){
	  int n;
	    if( !pObj->type->isLine ){
		        pik_error(p, pToken, "use with line-oriented objects only");
			    return;
			      }
	      n = p->nTPath - 1;
	        if( n<1 && (pObj->mProp & A_FROM)==0 ){
			    pik_error(p, pToken, "no prior path points");
			        return;
				  }
		  p->thenFlag = 1;
}

/* Advance to the next entry in p->aTPath.  Return its index.
 * */
static int pik_next_rpath(Pik *p, PToken *pErr){
	  int n = p->nTPath - 1;
	    if( n+1>=(int)count(p->aTPath) ){
		        pik_error(0, pErr, "too many path elements");
			    return n;
			      }
	      n++;
	        p->nTPath++;
		  p->aTPath[n] = p->aTPath[n-1];
		    p->mTPath = 0;
		      return n;
}

/* Add a direction term to an object.  "up 0.5", or "left 3", or "down"
 * ** or "down 50%".
 * */
static void pik_add_direction(Pik *p, PToken *pDir, PRel *pVal){
	  PObj *pObj = p->cur;
	    int n;
	      int dir;
	        if( !pObj->type->isLine ){
			    if( pDir ){
				          pik_error(p, pDir, "use with line-oriented objects only");
					      }else{
						            PToken x = pik_next_semantic_token(&pObj->errTok);
							          pik_error(p, &x, "syntax error");
								      }
			        return;
				  }
		  pik_reset_samepath(p);
		    n = p->nTPath - 1;
		      if( p->thenFlag || p->mTPath==3 || n==0 ){
			          n = pik_next_rpath(p, pDir);
				      p->thenFlag = 0;
				        }
		        dir = pDir ? pDir->eCode : p->eDir;
			  switch( dir ){
				      case DIR_UP:
					             if( p->mTPath & 2 ) n = pik_next_rpath(p, pDir);
						            p->aTPath[n].y += pVal->rAbs + pObj->h*pVal->rRel;
							           p->mTPath |= 2;
								          break;
									      case DIR_DOWN:
									         if( p->mTPath & 2 ) n = pik_next_rpath(p, pDir);
										        p->aTPath[n].y -= pVal->rAbs + pObj->h*pVal->rRel;
											       p->mTPath |= 2;
											              break;
												          case DIR_RIGHT:
												             if( p->mTPath & 1 ) n = pik_next_rpath(p, pDir);
													            p->aTPath[n].x += pVal->rAbs + pObj->w*pVal->rRel;
														           p->mTPath |= 1;
															          break;
																      case DIR_LEFT:
																         if( p->mTPath & 1 ) n = pik_next_rpath(p, pDir);
																	        p->aTPath[n].x -= pVal->rAbs + pObj->w*pVal->rRel;
																		       p->mTPath |= 1;
																		              break;
																			        }
			    pObj->outDir = dir;
}

/* Process a movement attribute of one of these forms:
 * **
 * **         pDist   pHdgKW  rHdg    pEdgept
 * **     GO distance HEADING angle
 * **     GO distance               compasspoint
 * */
static void pik_move_hdg(
		  Pik *p,              /* The Pikchr context */
		    PRel *pDist,         /* Distance to move */
		      PToken *pHeading,    /* "heading" keyword if present */
		        PNum rHdg,           /* Angle argument to "heading" keyword */
			  PToken *pEdgept,     /* EDGEPT keyword "ne", "sw", etc... */
			    PToken *pErr         /* Token to use for error messages */
		){
	  PObj *pObj = p->cur;
	    int n;
	      PNum rDist = pDist->rAbs + pik_value(p,"linewid",7,0)*pDist->rRel;
	        if( !pObj->type->isLine ){
			    pik_error(p, pErr, "use with line-oriented objects only");
			        return;
				  }
		  pik_reset_samepath(p);
		    do{
			        n = pik_next_rpath(p, pErr);
				  }while( n<1 );
		      if( pHeading ){
			          if( rHdg<0.0 || rHdg>360.0 ){
					        pik_error(p, pHeading, "headings should be between 0 and 360");
						      return;
						          }
				    }else if( pEdgept->eEdge==CP_C ){
					        pik_error(p, pEdgept, "syntax error");
						    return;
						      }else{
							          rHdg = pik_hdg_angle[pEdgept->eEdge];
								    }
		      if( rHdg<=45.0 ){
			          pObj->outDir = DIR_UP;
				    }else if( rHdg<=135.0 ){
					        pObj->outDir = DIR_RIGHT;
						  }else if( rHdg<=225.0 ){
							      pObj->outDir = DIR_DOWN;
							        }else if( rHdg<=315.0 ){
									    pObj->outDir = DIR_LEFT;
									      }else{
										          pObj->outDir = DIR_UP;
											    }
		        rHdg *= 0.017453292519943295769;  /* degrees to radians */
			  p->aTPath[n].x += rDist*sin(rHdg);
			    p->aTPath[n].y += rDist*cos(rHdg);
			      p->mTPath = 2;
}


/* Process a movement attribute of the form "right until even with ..."
 * **
 * ** pDir is the first keyword, "right" or "left" or "up" or "down".
 * ** The movement is in that direction until its closest approach to
 * ** the point specified by pPoint.
 * */
static void pik_evenwith(Pik *p, PToken *pDir, PPoint *pPlace){
	  PObj *pObj = p->cur;
	    int n;
	      if( !pObj->type->isLine ){
		          pik_error(p, pDir, "use with line-oriented objects only");
			      return;
			        }
	        pik_reset_samepath(p);
		  n = p->nTPath - 1;
		    if( p->thenFlag || p->mTPath==3 || n==0 ){
			        n = pik_next_rpath(p, pDir);
				    p->thenFlag = 0;
				      }
		      switch( pDir->eCode ){
			          case DIR_DOWN:
					      case DIR_UP:
					         if( p->mTPath & 2 ) n = pik_next_rpath(p, pDir);
						        p->aTPath[n].y = pPlace->y;
							       p->mTPath |= 2;
							              break;
								          case DIR_RIGHT:
								          case DIR_LEFT:
								             if( p->mTPath & 1 ) n = pik_next_rpath(p, pDir);
									            p->aTPath[n].x = pPlace->x;
										           p->mTPath |= 1;
											          break;
												    }
		        pObj->outDir = pDir->eCode;
}

/* Set the "from" of an object
 * */
static void pik_set_from(Pik *p, PObj *pObj, PToken *pTk, PPoint *pPt){
	  if( !pObj->type->isLine ){
		      pik_error(p, pTk, "use \"at\" to position this object");
		          return;
			    }
	    if( pObj->mProp & A_FROM ){
		        pik_error(p, pTk, "line start location already fixed");
			    return;
			      }
	      if( pObj->bClose ){
		          pik_error(p, pTk, "polygon is closed");
			      return;
			        }
	        if( p->nTPath>1 ){
			    PNum dx = pPt->x - p->aTPath[0].x;
			        PNum dy = pPt->y - p->aTPath[0].y;
				    int i;
				        for(i=1; i<p->nTPath; i++){
						      p->aTPath[i].x += dx;
						            p->aTPath[i].y += dy;
							        }
					  }
		  p->aTPath[0] = *pPt;
		    p->mTPath = 3;
		      pObj->mProp |= A_FROM;
}

/* Set the "to" of an object
 * */
static void pik_add_to(Pik *p, PObj *pObj, PToken *pTk, PPoint *pPt){
	  int n = p->nTPath-1;
	    if( !pObj->type->isLine ){
		        pik_error(p, pTk, "use \"at\" to position this object");
			    return;
			      }
	      if( pObj->bClose ){
		          pik_error(p, pTk, "polygon is closed");
			      return;
			        }
	        if( n==0 || p->mTPath==3 || p->thenFlag ){
			    n = pik_next_rpath(p, pTk);
			      }
		  p->aTPath[n] = *pPt;
		    p->mTPath = 3;
}

static void pik_close_path(Pik *p, PToken *pErr){
	  PObj *pObj = p->cur;
	    if( p->nTPath<3 ){
		        pik_error(p, pErr,
					      "need at least 3 vertexes in order to close the polygon");
			    return;
			      }
	      if( pObj->bClose ){
		          pik_error(p, pErr, "polygon already closed");
			      return;
			        }
	        pObj->bClose = 1;
}

/* Lower the layer of the current object so that it is behind the
 * ** given object.
 * */
static void pik_behind(Pik *p, PObj *pOther){
	  PObj *pObj = p->cur;
	    if( p->nErr==0 && pObj->iLayer>=pOther->iLayer ){
		        pObj->iLayer = pOther->iLayer - 1;
			  }
}


/* Set the "at" of an object
 * */
static void pik_set_at(Pik *p, PToken *pEdge, PPoint *pAt, PToken *pErrTok){
	  PObj *pObj;
	    static unsigned char eDirToCp[] = { CP_E, CP_S, CP_W, CP_N };
	      if( p->nErr ) return;
	        pObj = p->cur;

		  if( pObj->type->isLine ){
			      pik_error(p, pErrTok, "use \"from\" and \"to\" to position this object");
			          return;
				    }
		    if( pObj->mProp & A_AT ){
			        pik_error(p, pErrTok, "location fixed by prior \"at\"");
				    return;
				      }
		      pObj->mProp |= A_AT;
		        pObj->eWith = pEdge ? pEdge->eEdge : CP_C;
			  if( pObj->eWith>=CP_END ){
				      int dir = pObj->eWith==CP_END ? pObj->outDir : pObj->inDir;
				          pObj->eWith = eDirToCp[dir];
					    }
			    pObj->with = *pAt;
}

/*
 * ** Try to add a text attribute to an object
 * */
static void pik_add_txt(Pik *p, PToken *pTxt, int iPos){
	  PObj *pObj = p->cur;
	    PToken *pT;
	      if( pObj->nTxt >= count(pObj->aTxt) ){
		          pik_error(p, pTxt, "too many text terms");
			      return;
			        }
	        pT = &pObj->aTxt[pObj->nTxt++];
		  *pT = *pTxt;
		    pT->eCode = iPos;
}

/* Merge "text-position" flags
 * */
static int pik_text_position(int iPrev, PToken *pFlag){
	  int iRes = iPrev;
	    switch( pFlag->eType ){
		        case T_LJUST:    iRes = (iRes&~TP_JMASK) | TP_LJUST;  break;
					     case T_RJUST:    iRes = (iRes&~TP_JMASK) | TP_RJUST;  break;
							          case T_ABOVE:    iRes = (iRes&~TP_VMASK) | TP_ABOVE;  break;
										       case T_CENTER:   iRes = (iRes&~TP_VMASK) | TP_CENTER; break;
													    case T_BELOW:    iRes = (iRes&~TP_VMASK) | TP_BELOW;  break;
															         case T_ITALIC:   iRes |= TP_ITALIC;                   break; 
																		      case T_BOLD:     iRes |= TP_BOLD;                     break; 
																				           case T_ALIGNED:  iRes |= TP_ALIGN;                    break;
																							        case T_BIG:      if( iRes & TP_BIG ) iRes |= TP_XTRA;
																											                      else iRes = (iRes &~TP_SZMASK)|TP_BIG;   break;
																													          case T_SMALL:    if( iRes & TP_SMALL ) iRes |= TP_XTRA;
																																	                        else iRes = (iRes &~TP_SZMASK)|TP_SMALL; break;
																																				  }
	      return iRes;
}

/*
 * ** Table of scale-factor estimates for variable-width characters.
 * ** Actual character widths vary by font.  These numbers are only
 * ** guesses.  And this table only provides data for ASCII.
 * **
 * ** 100 means normal width.
 * */
static const unsigned char awChar[] = {
	  /* Skip initial 32 control characters */
	  /* ' ' */  45,
	    /* '!' */  55,
	      /* '"' */  62,
	        /* '#' */  115,
		  /* '$' */  90,
		    /* '%' */  132,
		      /* '&' */  125,
		        /* '\''*/  40,

			  /* '(' */  55,
			    /* ')' */  55,
			      /* '*' */  71,
			        /* '+' */  115,
				  /* ',' */  45,
				    /* '-' */  48,
				      /* '.' */  45,
				        /* '/' */  50,

					  /* '0' */  91,
					    /* '1' */  91,
					      /* '2' */  91,
					        /* '3' */  91,
						  /* '4' */  91,
						    /* '5' */  91,
						      /* '6' */  91,
						        /* '7' */  91,

							  /* '8' */  91,
							    /* '9' */  91,
							      /* ':' */  50,
							        /* ';' */  50,
								  /* '<' */ 120,
								    /* '=' */ 120,
								      /* '>' */ 120,
								        /* '?' */  78,

									  /* '@' */ 142,
									    /* 'A' */ 102,
									      /* 'B' */ 105,
									        /* 'C' */ 110,
										  /* 'D' */ 115,
										    /* 'E' */ 105,
										      /* 'F' */  98,
										        /* 'G' */ 105,

											  /* 'H' */ 125,
											    /* 'I' */  58,
											      /* 'J' */  58,
											        /* 'K' */ 107,
												  /* 'L' */  95,
												    /* 'M' */ 145,
												      /* 'N' */ 125,
												        /* 'O' */ 115,

													  /* 'P' */  95,
													    /* 'Q' */ 115,
													      /* 'R' */ 107,
													        /* 'S' */  95,
														  /* 'T' */  97,
														    /* 'U' */ 118,
														      /* 'V' */ 102,
														        /* 'W' */ 150,

															  /* 'X' */ 100,
															    /* 'Y' */  93,
															      /* 'Z' */ 100,
															        /* '[' */  58,
																  /* '\\'*/  50,
																    /* ']' */  58,
																      /* '^' */ 119,
																        /* '_' */  72,

																	  /* '`' */  72,
																	    /* 'a' */  86,
																	      /* 'b' */  92,
																	        /* 'c' */  80,
																		  /* 'd' */  92,
																		    /* 'e' */  85,
																		      /* 'f' */  52,
																		        /* 'g' */  92,

																			  /* 'h' */  92,
																			    /* 'i' */  47,
																			      /* 'j' */  47,
																			        /* 'k' */  88,
																				  /* 'l' */  48,
																				    /* 'm' */ 135,
																				      /* 'n' */  92,
																				        /* 'o' */  86,

																					  /* 'p' */  92,
																					    /* 'q' */  92,
																					      /* 'r' */  69,
																					        /* 's' */  75,
																						  /* 't' */  58,
																						    /* 'u' */  92,
																						      /* 'v' */  80,
																						        /* 'w' */ 121,

																							  /* 'x' */  81,
																							    /* 'y' */  80,
																							      /* 'z' */  76,
																							        /* '{' */  91,
																								  /* '|'*/   49,
																								    /* '}' */  91,
																								      /* '~' */ 118,
};

/* Return an estimate of the width of the displayed characters
 * ** in a character string.  The returned value is 100 times the
 * ** average character width.
 * **
 * ** Omit "\" used to escape characters.  And count entities like
 * ** "&lt;" as a single character.  Multi-byte UTF8 characters count
 * ** as a single character.
 * **
 * ** Attempt to scale the answer by the actual characters seen.  Wide
 * ** characters count more than narrow characters.  But the widths are
 * ** only guesses.
 * */
static int pik_text_length(const PToken *pToken){
	  int n = pToken->n;
	    const char *z = pToken->z;
	      int cnt, j;
	        for(j=1, cnt=0; j<n-1; j++){
			    char c = z[j];
			        if( c=='\\' && z[j+1]!='&' ){
					      c = z[++j];
					          }else if( c=='&' ){
							        int k;
								      for(k=j+1; k<j+7 && z[k]!=0 && z[k]!=';'; k++){}
								            if( z[k]==';' ) j = k;
									          cnt += 150;
										        continue;
											    }
				    if( (c & 0xc0)==0xc0 ){
					          while( j+1<n-1 && (z[j+1]&0xc0)==0x80 ){ j++; }
						        cnt += 100;
							      continue;
							          }
				        if( c>=0x20 && c<=0x7e ){
						      cnt += awChar[c-0x20];
						          }else{
								        cnt += 100;
									    }
					  }
		  return cnt;
}

/* Adjust the width, height, and/or radius of the object so that
 * ** it fits around the text that has been added so far.
 * **
 * **    (1) Only text specified prior to this attribute is considered.
 * **    (2) The text size is estimated based on the charht and charwid
 * **        variable settings.
 * **    (3) The fitted attributes can be changed again after this
 * **        attribute, for example using "width 110%" if this auto-fit
 * **        underestimates the text size.
 * **    (4) Previously set attributes will not be altered.  In other words,
 * **        "width 1in fit" might cause the height to change, but the
 * **        width is now set.
 * **    (5) This only works for attributes that have an xFit method.
 * **
 * ** The eWhich parameter is:
 * **
 * **    1:   Fit horizontally only
 * **    2:   Fit vertically only
 * **    3:   Fit both ways
 * */
static void pik_size_to_fit(Pik *p, PToken *pFit, int eWhich){
	  PObj *pObj;
	    PNum w, h;
	      PBox bbox;
	        if( p->nErr ) return;
		  pObj = p->cur;

		    if( pObj->nTxt==0 ){
			        pik_error(0, pFit, "no text to fit to");
				    return;
				      }
		      if( pObj->type->xFit==0 ) return;
		        pik_bbox_init(&bbox);
			  pik_compute_layout_settings(p);
			    pik_append_txt(p, pObj, &bbox);
			      w = (eWhich & 1)!=0 ? (bbox.ne.x - bbox.sw.x) + p->charWidth : 0;
			        h = (eWhich & 2)!=0 ? (bbox.ne.y - bbox.sw.y) + 0.5*p->charHeight : 0;
				  pObj->type->xFit(p, pObj, w, h);
				    pObj->mProp |= A_FIT;
}

/* Set a local variable name to "val".
 * **
 * ** The name might be a built-in variable or a color name.  In either case,
 * ** a new application-defined variable is set.  Since app-defined variables
 * ** are searched first, this will override any built-in variables.
 * */
static void pik_set_var(Pik *p, PToken *pId, PNum val, PToken *pOp){
	  PVar *pVar = p->pVar;
	    while( pVar ){
		        if( pik_token_eq(pId,pVar->zName)==0 ) break;
			    pVar = pVar->pNext;
			      }
	      if( pVar==0 ){
		          char *z;
			      pVar = malloc( pId->n+1 + sizeof(*pVar) );
			          if( pVar==0 ){
					        pik_error(p, 0, 0);
						      return;
						          }
				      pVar->zName = z = (char*)&pVar[1];
				          memcpy(z, pId->z, pId->n);
					      z[pId->n] = 0;
					          pVar->pNext = p->pVar;
						      pVar->val = pik_value(p, pId->z, pId->n, 0);
						          p->pVar = pVar;
							    }
	        switch( pOp->eCode ){
			    case T_PLUS:  pVar->val += val; break;
					      case T_STAR:  pVar->val *= val; break;
							        case T_MINUS: pVar->val -= val; break;
									          case T_SLASH:
									            if( val==0.0 ){
											            pik_error(p, pOp, "division by zero");
												          }else{
														          pVar->val /= val;
															        }
										          break;
											      default:      pVar->val = val; break;
													      }
		  p->bLayoutVars = 0;  /* Clear the layout setting cache */
}

/*
 * ** Search for the variable named z[0..n-1] in:
 * **
 * **   * Application defined variables
 * **   * Built-in variables
 * **
 * ** Return the value of the variable if found.  If not found
 * ** return 0.0.  Also if pMiss is not NULL, then set it to 1
 * ** if not found.
 * **
 * ** This routine is a subroutine to pik_get_var().  But it is also
 * ** used by object implementations to look up (possibly overwritten)
 * ** values for built-in variables like "boxwid".
 * */
static PNum pik_value(Pik *p, const char *z, int n, int *pMiss){
	  PVar *pVar;
	    int first, last, mid, c;
	      for(pVar=p->pVar; pVar; pVar=pVar->pNext){
		          if( strncmp(pVar->zName,z,n)==0 && pVar->zName[n]==0 ){
				        return pVar->val;
					    }
			    }
	        first = 0;
		  last = count(aBuiltin)-1;
		    while( first<=last ){
			        mid = (first+last)/2;
				    c = strncmp(z,aBuiltin[mid].zName,n);
				        if( c==0 && aBuiltin[mid].zName[n] ) c = 1;
					    if( c==0 ) return aBuiltin[mid].val;
					        if( c>0 ){
							      first = mid+1;
							          }else{
									        last = mid-1;
										    }
						  }
		      if( pMiss ) *pMiss = 1;
		        return 0.0;
}

/*
 * ** Look up a color-name.  Unlike other names in this program, the
 * ** color-names are not case sensitive.  So "DarkBlue" and "darkblue"
 * ** and "DARKBLUE" all find the same value (139).
 * **
 * ** If not found, return -99.0.  Also post an error if p!=NULL.
 * **
 * ** Special color names "None" and "Off" return -1.0 without causing
 * ** an error.
 * */
static PNum pik_lookup_color(Pik *p, PToken *pId){
	  int first, last, mid, c = 0;
	    first = 0;
	      last = count(aColor)-1;
	        while( first<=last ){
			    const char *zClr;
			        int c1, c2;
				    unsigned int i;
				        mid = (first+last)/2;
					    zClr = aColor[mid].zName;
					        for(i=0; i<pId->n; i++){
							      c1 = zClr[i]&0x7f;
							            if( isupper(c1) ) c1 = tolower(c1);
								          c2 = pId->z[i]&0x7f;
									        if( isupper(c2) ) c2 = tolower(c2);
										      c = c2 - c1;
										            if( c ) break;
											        }
						    if( c==0 && aColor[mid].zName[pId->n] ) c = -1;
						        if( c==0 ) return (double)aColor[mid].val;
							    if( c>0 ){
								          first = mid+1;
									      }else{
										            last = mid-1;
											        }
							      }
		  if( p ) pik_error(p, pId, "not a known color name");
		    return -99.0;
}

/* Get the value of a variable.
 * **
 * ** Search in order:
 * **
 * **    *  Application defined variables
 * **    *  Built-in variables
 * **    *  Color names
 * **
 * ** If no such variable is found, throw an error.
 * */
static PNum pik_get_var(Pik *p, PToken *pId){
	  int miss = 0;
	    PNum v = pik_value(p, pId->z, pId->n, &miss);
	      if( miss==0 ) return v;
	        v = pik_lookup_color(0, pId);
		  if( v>-90.0 ) return v;
		    pik_error(p,pId,"no such variable");
		      return 0.0;
}

/* Convert a T_NTH token (ex: "2nd", "5th"} into a numeric value and
 * ** return that value.  Throw an error if the value is too big.
 * */
static short int pik_nth_value(Pik *p, PToken *pNth){
	  int i = atoi(pNth->z);
	    if( i>1000 ){
		        pik_error(p, pNth, "value too big - max '1000th'");
			    i = 1;
			      }
	      if( i==0 && pik_token_eq(pNth,"first")==0 ) i = 1;
	        return i;
}

/* Search for the NTH object.
 * **
 * ** If pBasis is not NULL then it should be a [] object.  Use the
 * ** sublist of that [] object for the search.  If pBasis is not a []
 * ** object, then throw an error.
 * **
 * ** The pNth token describes the N-th search.  The pNth->eCode value
 * ** is one more than the number of items to skip.  It is negative
 * ** to search backwards.  If pNth->eType==T_ID, then it is the name
 * ** of a class to search for.  If pNth->eType==T_LB, then
 * ** search for a [] object.  If pNth->eType==T_LAST, then search for
 * ** any type.
 * **
 * ** Raise an error if the item is not found.
 * */
static PObj *pik_find_nth(Pik *p, PObj *pBasis, PToken *pNth){
	  PList *pList;
	    int i, n;
	      const PClass *pClass;
	        if( pBasis==0 ){
			    pList = p->list;
			      }else{
				          pList = pBasis->pSublist;
					    }
		  if( pList==0 ){
			      pik_error(p, pNth, "no such object");
			          return 0;
				    }
		    if( pNth->eType==T_LAST ){
			        pClass = 0;
				  }else if( pNth->eType==T_LB ){
					      pClass = &sublistClass;
					        }else{
							    pClass = pik_find_class(pNth);
							        if( pClass==0 ){
									      pik_error(0, pNth, "no such object type");
									            return 0;
										        }
								  }
		      n = pNth->eCode;
		        if( n<0 ){
				    for(i=pList->n-1; i>=0; i--){
					          PObj *pObj = pList->a[i];
						        if( pClass && pObj->type!=pClass ) continue;
							      n++;
							            if( n==0 ){ return pObj; }
								        }
				      }else{
					          for(i=0; i<pList->n; i++){
							        PObj *pObj = pList->a[i];
								      if( pClass && pObj->type!=pClass ) continue;
								            n--;
									          if( n==0 ){ return pObj; }
										      }
						    }
			  pik_error(p, pNth, "no such object");
			    return 0;
}

/* Search for an object by name.
 * **
 * ** Search in pBasis->pSublist if pBasis is not NULL.  If pBasis is NULL
 * ** then search in p->list.
 * */
static PObj *pik_find_byname(Pik *p, PObj *pBasis, PToken *pName){
	  PList *pList;
	    int i, j;
	      if( pBasis==0 ){
		          pList = p->list;
			    }else{
				        pList = pBasis->pSublist;
					  }
	        if( pList==0 ){
			    pik_error(p, pName, "no such object");
			        return 0;
				  }
		  /* First look explicitly tagged objects */
		  for(i=pList->n-1; i>=0; i--){
			      PObj *pObj = pList->a[i];
			          if( pObj->zName && pik_token_eq(pName,pObj->zName)==0 ){
					        return pObj;
						    }
				    }
		    /* If not found, do a second pass looking for any object containing
		     *   ** text which exactly matches pName */
		    for(i=pList->n-1; i>=0; i--){
			        PObj *pObj = pList->a[i];
				    for(j=0; j<pObj->nTxt; j++){
					          if( pObj->aTxt[j].n==pName->n+2
								         && memcmp(pObj->aTxt[j].z+1,pName->z,pName->n)==0 ){
							          return pObj;
								        }
						      }
				      }
		      pik_error(p, pName, "no such object");
		        return 0;
}

/* Change most of the settings for the current object to be the
 * ** same as the pOther object, or the most recent object of the same
 * ** type if pOther is NULL.
 * */
static void pik_same(Pik *p, PObj *pOther, PToken *pErrTok){
	  PObj *pObj = p->cur;
	    if( p->nErr ) return;
	      if( pOther==0 ){
		          int i;
			      for(i=(p->list ? p->list->n : 0)-1; i>=0; i--){
				            pOther = p->list->a[i];
					          if( pOther->type==pObj->type ) break;
						      }
			          if( i<0 ){
					        pik_error(p, pErrTok, "no prior objects of the same type");
						      return;
						          }
				    }
	        if( pOther->nPath && pObj->type->isLine ){
			    PNum dx, dy;
			        int i;
				    dx = p->aTPath[0].x - pOther->aPath[0].x;
				        dy = p->aTPath[0].y - pOther->aPath[0].y;
					    for(i=1; i<pOther->nPath; i++){
						          p->aTPath[i].x = pOther->aPath[i].x + dx;
							        p->aTPath[i].y = pOther->aPath[i].y + dy;
								    }
					        p->nTPath = pOther->nPath;
						    p->mTPath = 3;
						        p->samePath = 1;
							  }
		  if( !pObj->type->isLine ){
			      pObj->w = pOther->w;
			          pObj->h = pOther->h;
				    }
		    pObj->rad = pOther->rad;
		      pObj->sw = pOther->sw;
		        pObj->dashed = pOther->dashed;
			  pObj->dotted = pOther->dotted;
			    pObj->fill = pOther->fill;
			      pObj->color = pOther->color;
			        pObj->cw = pOther->cw;
				  pObj->larrow = pOther->larrow;
				    pObj->rarrow = pOther->rarrow;
				      pObj->bClose = pOther->bClose;
				        pObj->bChop = pOther->bChop;
					  pObj->inDir = pOther->inDir;
					    pObj->outDir = pOther->outDir;
					      pObj->iLayer = pOther->iLayer;
}


/* Return a "Place" associated with object pObj.  If pEdge is NULL
 * ** return the center of the object.  Otherwise, return the corner
 * ** described by pEdge.
 * */
static PPoint pik_place_of_elem(Pik *p, PObj *pObj, PToken *pEdge){
	  PPoint pt = cZeroPoint;
	    const PClass *pClass;
	      if( pObj==0 ) return pt;
	        if( pEdge==0 ){
			    return pObj->ptAt;
			      }
		  pClass = pObj->type;
		    if( pEdge->eType==T_EDGEPT || (pEdge->eEdge>0 && pEdge->eEdge<CP_END) ){
			        pt = pClass->xOffset(p, pObj, pEdge->eEdge);
				    pt.x += pObj->ptAt.x;
				        pt.y += pObj->ptAt.y;
					    return pt;
					      }
		      if( pEdge->eType==T_START ){
			          return pObj->ptEnter;
				    }else{
					        return pObj->ptExit;
						  }
}

/* Do a linear interpolation of two positions.
 * */
static PPoint pik_position_between(PNum x, PPoint p1, PPoint p2){
	  PPoint out;
	    out.x = p2.x*x + p1.x*(1.0 - x);
	      out.y = p2.y*x + p1.y*(1.0 - x);
	        return out;
}

/* Compute the position that is dist away from pt at an heading angle of r
 * **
 * ** The angle is a compass heading in degrees.  North is 0 (or 360).
 * ** East is 90.  South is 180.  West is 270.  And so forth.
 * */
static PPoint pik_position_at_angle(PNum dist, PNum r, PPoint pt){
	  r *= 0.017453292519943295769;  /* degrees to radians */
	    pt.x += dist*sin(r);
	      pt.y += dist*cos(r);
	        return pt;
}

/* Compute the position that is dist away at a compass point
 * */
static PPoint pik_position_at_hdg(PNum dist, PToken *pD, PPoint pt){
	  return pik_position_at_angle(dist, pik_hdg_angle[pD->eEdge], pt);
}

/* Return the coordinates for the n-th vertex of a line.
 * */
static PPoint pik_nth_vertex(Pik *p, PToken *pNth, PToken *pErr, PObj *pObj){
	  static const PPoint zero;
	    int n;
	      if( p->nErr || pObj==0 ) return p->aTPath[0];
	        if( !pObj->type->isLine ){
			    pik_error(p, pErr, "object is not a line");
			        return zero;
				  }
		  n = atoi(pNth->z);
		    if( n<1 || n>pObj->nPath ){
			        pik_error(p, pNth, "no such vertex");
				    return zero;
				      }
		      return pObj->aPath[n-1];
}

/* Return the value of a property of an object.
 * */
static PNum pik_property_of(PObj *pObj, PToken *pProp){
	  PNum v = 0.0;
	    switch( pProp->eType ){
		        case T_HEIGHT:    v = pObj->h;            break;
					      case T_WIDTH:     v = pObj->w;            break;
								    case T_RADIUS:    v = pObj->rad;          break;
										          case T_DIAMETER:  v = pObj->rad*2.0;      break;
													        case T_THICKNESS: v = pObj->sw;           break;
																      case T_DASHED:    v = pObj->dashed;       break;
																			    case T_DOTTED:    v = pObj->dotted;       break;
																					          case T_FILL:      v = pObj->fill;         break;
																								        case T_COLOR:     v = pObj->color;        break;
																											      case T_X:         v = pObj->ptAt.x;       break;
																														    case T_Y:         v = pObj->ptAt.y;       break;
																																          case T_TOP:       v = pObj->bbox.ne.y;    break;
																																			        case T_BOTTOM:    v = pObj->bbox.sw.y;    break;
																																						      case T_LEFT:      v = pObj->bbox.sw.x;    break;
																																									    case T_RIGHT:     v = pObj->bbox.ne.x;    break;
																																											        }
	      return v;
}

/* Compute one of the built-in functions
 * */
static PNum pik_func(Pik *p, PToken *pFunc, PNum x, PNum y){
	  PNum v = 0.0;
	    switch( pFunc->eCode ){
		        case FN_ABS:  v = v<0.0 ? -v : v;  break;
				          case FN_COS:  v = cos(x);          break;
							    case FN_INT:  v = rint(x);         break;
									      case FN_SIN:  v = sin(x);          break;
											        case FN_SQRT:
											          if( x<0.0 ){
													          pik_error(p, pFunc, "sqrt of negative value");
														          v = 0.0;
															        }else{
																	        v = sqrt(x);
																		      }
												        break;
													    case FN_MAX:  v = x>y ? x : y;   break;
															      case FN_MIN:  v = x<y ? x : y;   break;
																	        default:      v = 0.0;
																			        }
	      return v;
}

/* Attach a name to an object
 * */
static void pik_elem_setname(Pik *p, PObj *pObj, PToken *pName){
	  if( pObj==0 ) return;
	    if( pName==0 ) return;
	      free(pObj->zName);
	        pObj->zName = malloc(pName->n+1);
		  if( pObj->zName==0 ){
			      pik_error(p,0,0);
			        }else{
					    memcpy(pObj->zName,pName->z,pName->n);
					        pObj->zName[pName->n] = 0;
						  }
		    return;
}

/*
 * ** Search for object located at *pCenter that has an xChop method.
 * ** Return a pointer to the object, or NULL if not found.
 * */
static PObj *pik_find_chopper(PList *pList, PPoint *pCenter){
	  int i;
	    if( pList==0 ) return 0;
	      for(i=pList->n-1; i>=0; i--){
		          PObj *pObj = pList->a[i];
			      if( pObj->type->xChop!=0
					           && pObj->ptAt.x==pCenter->x
						        && pObj->ptAt.y==pCenter->y
							    ){
				            return pObj;
					        }else if( pObj->pSublist ){
							      pObj = pik_find_chopper(pObj->pSublist,pCenter);
							            if( pObj ) return pObj;
								        }
			        }
	        return 0;
}

/*
 * ** There is a line traveling from pFrom to pTo.
 * **
 * ** If point pTo is the exact enter of a choppable object,
 * ** then adjust pTo by the appropriate amount in the direction
 * ** of pFrom.
 * */
static void pik_autochop(Pik *p, PPoint *pFrom, PPoint *pTo){
	  PObj *pObj = pik_find_chopper(p->list, pTo);
	    if( pObj ){
		        *pTo = pObj->type->xChop(p, pObj, pFrom);
			  }
}

/* This routine runs after all attributes have been received
 * ** on an object.
 * */
static void pik_after_adding_attributes(Pik *p, PObj *pObj){
	  int i;
	    PPoint ofst;
	      PNum dx, dy;

	        if( p->nErr ) return;

		  /* Position block objects */
		  if( pObj->type->isLine==0 ){
			      /* A height or width less than or equal to zero means "autofit".
			       *     ** Change the height or width to be big enough to contain the text,
			       *         */
			      if( pObj->h<=0.0 ){
				            if( pObj->nTxt==0 ){
						            pObj->h = 0.0;
							          }else if( pObj->w<=0.0 ){
									          pik_size_to_fit(p, &pObj->errTok, 3);
										        }else{
												        pik_size_to_fit(p, &pObj->errTok, 2);
													      }
					        }
			          if( pObj->w<=0.0 ){
					        if( pObj->nTxt==0 ){
							        pObj->w = 0.0;
								      }else{
									              pik_size_to_fit(p, &pObj->errTok, 1);
										            }
						    }
				      ofst = pik_elem_offset(p, pObj, pObj->eWith);
				          dx = (pObj->with.x - ofst.x) - pObj->ptAt.x;
					      dy = (pObj->with.y - ofst.y) - pObj->ptAt.y;
					          if( dx!=0 || dy!=0 ){
							        pik_elem_move(pObj, dx, dy);
								    }
						    }

		    /* For a line object with no movement specified, a single movement
		     *   ** of the default length in the current direction
		     *     */
		    if( pObj->type->isLine && p->nTPath<2 ){
			        pik_next_rpath(p, 0);
				    assert( p->nTPath==2 );
				        switch( pObj->inDir ){
						      default:        p->aTPath[1].x += pObj->w; break;
								            case DIR_DOWN:  p->aTPath[1].y -= pObj->h; break;
											          case DIR_LEFT:  p->aTPath[1].x -= pObj->w; break;
														        case DIR_UP:    p->aTPath[1].y += pObj->h; break;
																	    }
					    if( pObj->type->xInit==arcInit ){
						          p->eDir = pObj->outDir = (pObj->inDir + (pObj->cw ? 1 : 3))%4;
							        switch( pObj->outDir ){
									        default:        p->aTPath[1].x += pObj->w; break;
												        case DIR_DOWN:  p->aTPath[1].y -= pObj->h; break;
															        case DIR_LEFT:  p->aTPath[1].x -= pObj->w; break;
																		        case DIR_UP:    p->aTPath[1].y += pObj->h; break;
																					      }
								    }
					      }

		      /* Initialize the bounding box prior to running xCheck */
		      pik_bbox_init(&pObj->bbox);

		        /* Run object-specific code */
		        if( pObj->type->xCheck!=0 ){
				    pObj->type->xCheck(p,pObj);
				        if( p->nErr ) return;
					  }

			  /* Compute final bounding box, entry and exit points, center
			   *   ** point (ptAt) and path for the object
			   *     */
			  if( pObj->type->isLine ){
				      pObj->aPath = malloc( sizeof(PPoint)*p->nTPath );
				          if( pObj->aPath==0 ){
						        pik_error(p, 0, 0);
							      return;
							          }else{
									        pObj->nPath = p->nTPath;
										      for(i=0; i<p->nTPath; i++){
											              pObj->aPath[i] = p->aTPath[i];
												            }
										          }

					      /* "chop" processing:
					       *     ** If the line goes to the center of an object with an
					       *         ** xChop method, then use the xChop method to trim the line.
					       *             */
					      if( pObj->bChop && pObj->nPath>=2 ){
						            int n = pObj->nPath;
							          pik_autochop(p, &pObj->aPath[n-2], &pObj->aPath[n-1]);
								        pik_autochop(p, &pObj->aPath[1], &pObj->aPath[0]);
									    }

					          pObj->ptEnter = pObj->aPath[0];
						      pObj->ptExit = pObj->aPath[pObj->nPath-1];

						          /* Compute the center of the line based on the bounding box over
							   *     ** the vertexes.  This is a difference from PIC.  In Pikchr, the
							   *         ** center of a line is the center of its bounding box. In PIC, the
							   *             ** center of a line is halfway between its .start and .end.  For
							   *                 ** straight lines, this is the same point, but for multi-segment
							   *                     ** lines the result is usually diferent */
						          for(i=0; i<pObj->nPath; i++){
								        pik_bbox_add_xy(&pObj->bbox, pObj->aPath[i].x, pObj->aPath[i].y);
									    }
							      pObj->ptAt.x = (pObj->bbox.ne.x + pObj->bbox.sw.x)/2.0;
							          pObj->ptAt.y = (pObj->bbox.ne.y + pObj->bbox.sw.y)/2.0;

								      /* Reset the width and height of the object to be the width and height
								       *     ** of the bounding box over vertexes */
								      pObj->w = pObj->bbox.ne.x - pObj->bbox.sw.x;
								          pObj->h = pObj->bbox.ne.y - pObj->bbox.sw.y;

									      /* If this is a polygon (if it has the "close" attribute), then
									       *     ** adjust the exit point */
									      if( pObj->bClose ){
										            /* For "closed" lines, the .end is one of the .e, .s, .w, or .n
											     *       ** points of the bounding box, as with block objects. */
										            pik_elem_set_exit(pObj, pObj->inDir);
											        }
									        }else{
											    PNum w2 = pObj->w/2.0;
											        PNum h2 = pObj->h/2.0;
												    pObj->ptEnter = pObj->ptAt;
												        pObj->ptExit = pObj->ptAt;
													    switch( pObj->inDir ){
														          default:         pObj->ptEnter.x -= w2;  break;
																	         case DIR_LEFT:   pObj->ptEnter.x += w2;  break;
																				        case DIR_UP:     pObj->ptEnter.y -= h2;  break;
																							       case DIR_DOWN:   pObj->ptEnter.y += h2;  break;
																										    }
													        switch( pObj->outDir ){
															      default:         pObj->ptExit.x += w2;  break;
																	             case DIR_LEFT:   pObj->ptExit.x -= w2;  break;
																				            case DIR_UP:     pObj->ptExit.y += h2;  break;
																							           case DIR_DOWN:   pObj->ptExit.y -= h2;  break;
																										        }
														    pik_bbox_add_xy(&pObj->bbox, pObj->ptAt.x - w2, pObj->ptAt.y - h2);
														        pik_bbox_add_xy(&pObj->bbox, pObj->ptAt.x + w2, pObj->ptAt.y + h2);
															  }
			    p->eDir = pObj->outDir;
}

/* Show basic information about each object as a comment in the
 * ** generated HTML.  Used for testing and debugging.  Activated
 * ** by the (undocumented) "debug = 1;"
 * ** command.
 * */
static void pik_elem_render(Pik *p, PObj *pObj){
	  char *zDir;
	    if( pObj==0 ) return;
	      pik_append(p,"<!-- ", -1);
	        if( pObj->zName ){
			    pik_append_text(p, pObj->zName, -1, 0);
			        pik_append(p, ": ", 2);
				  }
		  pik_append_text(p, pObj->type->zName, -1, 0);
		    if( pObj->nTxt ){
			        pik_append(p, " \"", 2);
				    pik_append_text(p, pObj->aTxt[0].z+1, pObj->aTxt[0].n-2, 1);
				        pik_append(p, "\"", 1);
					  }
		      pik_append_num(p, " w=", pObj->w);
		        pik_append_num(p, " h=", pObj->h);
			  pik_append_point(p, " center=", &pObj->ptAt);
			    pik_append_point(p, " enter=", &pObj->ptEnter);
			      switch( pObj->outDir ){
				          default:        zDir = " right";  break;
							      case DIR_LEFT:  zDir = " left";   break;
									          case DIR_UP:    zDir = " up";     break;
												      case DIR_DOWN:  zDir = " down";   break;
														        }
			        pik_append_point(p, " exit=", &pObj->ptExit);
				  pik_append(p, zDir, -1);
				    pik_append(p, " -->\n", -1);
}

/* Render a list of objects
 * */
void pik_elist_render(Pik *p, PList *pList){
	  int i;
	    int iNextLayer = 0;
	      int iThisLayer;
	        int bMoreToDo;
		  int miss = 0;
		    int mDebug = (int)pik_value(p, "debug", 5, 0);
		      PNum colorLabel;
		        do{
				    bMoreToDo = 0;
				        iThisLayer = iNextLayer;
					    iNextLayer = 0x7fffffff;
					        for(i=0; i<pList->n; i++){
							      PObj *pObj = pList->a[i];
							            if( pObj->iLayer>iThisLayer ){
									            if( pObj->iLayer<iNextLayer ) iNextLayer = pObj->iLayer;
										            bMoreToDo = 1;
											            continue; /* Defer until another round */
												          }else if( pObj->iLayer<iThisLayer ){
														          continue;
															        }
								          void (*xRender)(Pik*,PObj*);
									        if( mDebug & 1 ) pik_elem_render(p, pObj);
										      xRender = pObj->type->xRender;
										            if( xRender ){
												            xRender(p, pObj);
													          }
											          if( pObj->pSublist ){
													          pik_elist_render(p, pObj->pSublist);
														        }
												      }
						  }while( bMoreToDo );

			  /* If the color_debug_label value is defined, then go through
			   *   ** and paint a dot at every label location */
			  colorLabel = pik_value(p, "debug_label_color", 17, &miss);
			  if( miss==0 && colorLabel>=0.0 ){
				      PObj dot;
				          memset(&dot, 0, sizeof(dot));
					      dot.type = &noopClass;
					          dot.rad = 0.015;
						      dot.sw = 0.015;
						          dot.fill = colorLabel;
							      dot.color = colorLabel;
							          dot.nTxt = 1;
								      dot.aTxt[0].eCode = TP_ABOVE;
								          for(i=0; i<pList->n; i++){
										        PObj *pObj = pList->a[i];
											      if( pObj->zName==0 ) continue;
											            dot.ptAt = pObj->ptAt;
												          dot.aTxt[0].z = pObj->zName;
													        dot.aTxt[0].n = (int)strlen(pObj->zName);
														      dotRender(p, &dot);
														          }
									    }
}

/* Add all objects of the list pList to the bounding box
 * */
static void pik_bbox_add_elist(Pik *p, PList *pList, PNum wArrow){
	  int i;
	    for(i=0; i<pList->n; i++){
		        PObj *pObj = pList->a[i];
			    if( pObj->sw>0.0 ) pik_bbox_addbox(&p->bbox, &pObj->bbox);
			        pik_append_txt(p, pObj, &p->bbox);
				    if( pObj->pSublist ) pik_bbox_add_elist(p, pObj->pSublist, wArrow);


				        /* Expand the bounding box to account for arrowheads on lines */
				        if( pObj->type->isLine && pObj->nPath>0 ){
						      if( pObj->larrow ){
							              pik_bbox_addellipse(&p->bbox, pObj->aPath[0].x, pObj->aPath[0].y,
										                                  wArrow, wArrow);
								            }
						            if( pObj->rarrow ){
								            int j = pObj->nPath-1;
									            pik_bbox_addellipse(&p->bbox, pObj->aPath[j].x, pObj->aPath[j].y,
												                                wArrow, wArrow);
										          }
							        }
					  }
}

/* Recompute key layout parameters from variables. */
static void pik_compute_layout_settings(Pik *p){
	  PNum thickness;  /* Line thickness */
	    PNum wArrow;     /* Width of arrowheads */

	      /* Set up rendering parameters */
	      if( p->bLayoutVars ) return;
	        thickness = pik_value(p,"thickness",9,0);
		  if( thickness<=0.01 ) thickness = 0.01;
		    wArrow = 0.5*pik_value(p,"arrowwid",8,0);
		      p->wArrow = wArrow/thickness;
		        p->hArrow = pik_value(p,"arrowht",7,0)/thickness;
			  p->fontScale = pik_value(p,"fontscale",9,0);
			    if( p->fontScale<=0.0 ) p->fontScale = 1.0;
			      p->rScale = 144.0;
			        p->charWidth = pik_value(p,"charwid",7,0)*p->fontScale;
				  p->charHeight = pik_value(p,"charht",6,0)*p->fontScale;
				    p->bLayoutVars = 1;
}

/* Render a list of objects.  Write the SVG into p->zOut.
 * ** Delete the input object_list before returnning.
 * */
static void pik_render(Pik *p, PList *pList){
	  if( pList==0 ) return;
	    if( p->nErr==0 ){
		        PNum thickness;  /* Stroke width */
			    PNum margin;     /* Extra bounding box margin */
			        PNum w, h;       /* Drawing width and height */
				    PNum wArrow;
				        PNum pikScale;   /* Value of the "scale" variable */

					    /* Set up rendering parameters */
					    pik_compute_layout_settings(p);
					        thickness = pik_value(p,"thickness",9,0);
						    if( thickness<=0.01 ) thickness = 0.01;
						        margin = pik_value(p,"margin",6,0);
							    margin += thickness;
							        wArrow = p->wArrow*thickness;

								    /* Compute a bounding box over all objects so that we can know
								     *     ** how big to declare the SVG canvas */
								    pik_bbox_init(&p->bbox);
								        pik_bbox_add_elist(p, pList, wArrow);

									    /* Expand the bounding box slightly to account for line thickness
									     *     ** and the optional "margin = EXPR" setting. */
									    p->bbox.ne.x += margin + pik_value(p,"rightmargin",11,0);
									        p->bbox.ne.y += margin + pik_value(p,"topmargin",9,0);
										    p->bbox.sw.x -= margin + pik_value(p,"leftmargin",10,0);
										        p->bbox.sw.y -= margin + pik_value(p,"bottommargin",12,0);

											    /* Output the SVG */
											    pik_append(p, "<svg xmlns='http://www.w3.org/2000/svg'",-1);
											        if( p->zClass ){
													      pik_append(p, " class=\"", -1);
													            pik_append(p, p->zClass, -1);
														          pik_append(p, "\"", 1);
															      }
												    w = p->bbox.ne.x - p->bbox.sw.x;
												        h = p->bbox.ne.y - p->bbox.sw.y;
													    p->wSVG = (int)(p->rScale*w);
													        p->hSVG = (int)(p->rScale*h);
														    pikScale = pik_value(p,"scale",5,0);
														        if( pikScale<0.99 || pikScale>1.01 ){
																      p->wSVG *= pikScale;
																            p->hSVG *= pikScale;
																	          pik_append_num(p, " width=\"", p->wSVG);
																		        pik_append_num(p, "\" height=\"", p->hSVG);
																			      pik_append(p, "\"", 1);
																			          }
															    pik_append_dis(p, " viewBox=\"0 0 ",w,"");
															        pik_append_dis(p, " ",h,"\">\n");
																    pik_elist_render(p, pList);
																        pik_append(p,"</svg>\n", -1);
																	  }else{
																		      p->wSVG = -1;
																		          p->hSVG = -1;
																			    }
	      pik_elist_free(p, pList);
}



/*
 * ** An array of this structure defines a list of keywords.
 * */
typedef struct PikWord {
	  char *zWord;             /* Text of the keyword */
	    unsigned char nChar;     /* Length of keyword text in bytes */
	      unsigned char eType;     /* Token code */
	        unsigned char eCode;     /* Extra code for the token */
		  unsigned char eEdge;     /* CP_* code for corner/edge keywords */
} PikWord;

/*
 * ** Keywords
 * */
static const PikWord pik_keywords[] = {
	  { "above",      5,   T_ABOVE,     0,         0        },
	    { "abs",        3,   T_FUNC1,     FN_ABS,    0        },
	      { "aligned",    7,   T_ALIGNED,   0,         0        },
	        { "and",        3,   T_AND,       0,         0        },
		  { "as",         2,   T_AS,        0,         0        },
		    { "assert",     6,   T_ASSERT,    0,         0        },
		      { "at",         2,   T_AT,        0,         0        },
		        { "behind",     6,   T_BEHIND,    0,         0        },
			  { "below",      5,   T_BELOW,     0,         0        },
			    { "between",    7,   T_BETWEEN,   0,         0        },
			      { "big",        3,   T_BIG,       0,         0        },
			        { "bold",       4,   T_BOLD,      0,         0        },
				  { "bot",        3,   T_EDGEPT,    0,         CP_S     },
				    { "bottom",     6,   T_BOTTOM,    0,         CP_S     },
				      { "c",          1,   T_EDGEPT,    0,         CP_C     },
				        { "ccw",        3,   T_CCW,       0,         0        },
					  { "center",     6,   T_CENTER,    0,         CP_C     },
					    { "chop",       4,   T_CHOP,      0,         0        },
					      { "close",      5,   T_CLOSE,     0,         0        },
					        { "color",      5,   T_COLOR,     0,         0        },
						  { "cos",        3,   T_FUNC1,     FN_COS,    0        },
						    { "cw",         2,   T_CW,        0,         0        },
						      { "dashed",     6,   T_DASHED,    0,         0        },
						        { "define",     6,   T_DEFINE,    0,         0        },
							  { "diameter",   8,   T_DIAMETER,  0,         0        },
							    { "dist",       4,   T_DIST,      0,         0        },
							      { "dotted",     6,   T_DOTTED,    0,         0        },
							        { "down",       4,   T_DOWN,      DIR_DOWN,  0        },
								  { "e",          1,   T_EDGEPT,    0,         CP_E     },
								    { "east",       4,   T_EDGEPT,    0,         CP_E     },
								      { "end",        3,   T_END,       0,         CP_END   },
								        { "even",       4,   T_EVEN,      0,         0        },
									  { "fill",       4,   T_FILL,      0,         0        },
									    { "first",      5,   T_NTH,       0,         0        },
									      { "fit",        3,   T_FIT,       0,         0        },
									        { "from",       4,   T_FROM,      0,         0        },
										  { "go",         2,   T_GO,        0,         0        },
										    { "heading",    7,   T_HEADING,   0,         0        },
										      { "height",     6,   T_HEIGHT,    0,         0        },
										        { "ht",         2,   T_HEIGHT,    0,         0        },
											  { "in",         2,   T_IN,        0,         0        },
											    { "int",        3,   T_FUNC1,     FN_INT,    0        },
											      { "invis",      5,   T_INVIS,     0,         0        },
											        { "invisible",  9,   T_INVIS,     0,         0        },
												  { "italic",     6,   T_ITALIC,    0,         0        },
												    { "last",       4,   T_LAST,      0,         0        },
												      { "left",       4,   T_LEFT,      DIR_LEFT,  CP_W     },
												        { "ljust",      5,   T_LJUST,     0,         0        },
													  { "max",        3,   T_FUNC2,     FN_MAX,    0        },
													    { "min",        3,   T_FUNC2,     FN_MIN,    0        },
													      { "n",          1,   T_EDGEPT,    0,         CP_N     },
													        { "ne",         2,   T_EDGEPT,    0,         CP_NE    },
														  { "north",      5,   T_EDGEPT,    0,         CP_N     },
														    { "nw",         2,   T_EDGEPT,    0,         CP_NW    },
														      { "of",         2,   T_OF,        0,         0        },
														        { "previous",   8,   T_LAST,      0,         0,       },
															  { "print",      5,   T_PRINT,     0,         0        },
															    { "rad",        3,   T_RADIUS,    0,         0        },
															      { "radius",     6,   T_RADIUS,    0,         0        },
															        { "right",      5,   T_RIGHT,     DIR_RIGHT, CP_E     },
																  { "rjust",      5,   T_RJUST,     0,         0        },
																    { "s",          1,   T_EDGEPT,    0,         CP_S     },
																      { "same",       4,   T_SAME,      0,         0        },
																        { "se",         2,   T_EDGEPT,    0,         CP_SE    },
																	  { "sin",        3,   T_FUNC1,     FN_SIN,    0        },
																	    { "small",      5,   T_SMALL,     0,         0        },
																	      { "south",      5,   T_EDGEPT,    0,         CP_S     },
																	        { "sqrt",       4,   T_FUNC1,     FN_SQRT,   0        },
																		  { "start",      5,   T_START,     0,         CP_START },
																		    { "sw",         2,   T_EDGEPT,    0,         CP_SW    },
																		      { "t",          1,   T_TOP,       0,         CP_N     },
																		        { "the",        3,   T_THE,       0,         0        },
																			  { "then",       4,   T_THEN,      0,         0        },
																			    { "thick",      5,   T_THICK,     0,         0        },
																			      { "thickness",  9,   T_THICKNESS, 0,         0        },
																			        { "thin",       4,   T_THIN,      0,         0        },
																				  { "to",         2,   T_TO,        0,         0        },
																				    { "top",        3,   T_TOP,       0,         CP_N     },
																				      { "until",      5,   T_UNTIL,     0,         0        },
																				        { "up",         2,   T_UP,        DIR_UP,    0        },
																					  { "vertex",     6,   T_VERTEX,    0,         0        },
																					    { "w",          1,   T_EDGEPT,    0,         CP_W     },
																					      { "way",        3,   T_WAY,       0,         0        },
																					        { "west",       4,   T_EDGEPT,    0,         CP_W     },
																						  { "wid",        3,   T_WIDTH,     0,         0        },
																						    { "width",      5,   T_WIDTH,     0,         0        },
																						      { "with",       4,   T_WITH,      0,         0        },
																						        { "x",          1,   T_X,         0,         0        },
																							  { "y",          1,   T_Y,         0,         0        },
};

/*
 * ** Search a PikWordlist for the given keyword.  Return a pointer to the
 * ** keyword entry found.  Or return 0 if not found.
 * */
static const PikWord *pik_find_word(
		  const char *zIn,              /* Word to search for */
		    int n,                        /* Length of zIn */
		      const PikWord *aList,         /* List to search */
		        int nList                     /* Number of entries in aList */
		){
	  int first = 0;
	    int last = nList-1;
	      while( first<=last ){
		          int mid = (first + last)/2;
			      int sz = aList[mid].nChar;
			          int c = strncmp(zIn, aList[mid].zWord, sz<n ? sz : n);
				      if( c==0 ){
					            c = n - sz;
						          if( c==0 ) return &aList[mid];
							      }
				          if( c<0 ){
						        last = mid-1;
							    }else{
								          first = mid+1;
									      }
					    }
	        return 0;
}

/*
 * ** Set a symbolic debugger breakpoint on this routine to receive a
 * ** breakpoint when the "#breakpoint" token is parsed.
 * */
static void pik_breakpoint(const unsigned char *z){
	  /* Prevent C compilers from optimizing out this routine. */
	  if( z[2]=='X' ) exit(1);
}


/*
 * ** Return the length of next token.  The token starts on
 * ** the pToken->z character.  Fill in other fields of the
 * ** pToken object as appropriate.
 * */
static int pik_token_length(PToken *pToken, int bAllowCodeBlock){
	  const unsigned char *z = (const unsigned char*)pToken->z;
	    int i;
	      unsigned char c, c2;
	        switch( z[0] ){
			    case '\\': {
					             pToken->eType = T_WHITESPACE;
						           for(i=1; z[i]=='\r' || z[i]==' ' || z[i]=='\t'; i++){}
							         if( z[i]=='\n'  ) return i+1;
								       pToken->eType = T_ERROR;
								             return 1;
									         }
				           case ';':
				           case '\n': {
							            pToken->eType = T_EOL;
								          return 1;
									      }
						          case '"': {
									          for(i=1; (c = z[i])!=0; i++){
											          if( c=='\\' ){ 
													            if( z[i+1]==0 ) break;
														              i++;
															                continue;
																	        }
												          if( c=='"' ){
														            pToken->eType = T_STRING;
															              return i+1;
																              }
													        }
										        pToken->eType = T_ERROR;
											      return i;
											          }
								        case ' ':
								        case '\t':
								        case '\f':
								        case '\r': {
											         for(i=1; (c = z[i])==' ' || c=='\t' || c=='\r' || c=='\t'; i++){}
												       pToken->eType = T_WHITESPACE;
												             return i;
													         }
										       case '#': {
													       for(i=1; (c = z[i])!=0 && c!='\n'; i++){}
													             pToken->eType = T_WHITESPACE;
														           /* If the comment is "#breakpoint" then invoke the pik_breakpoint()
															    *       ** routine.  The pik_breakpoint() routie is a no-op that serves as
															    *             ** a convenient place to set a gdb breakpoint when debugging. */
														           if( strncmp((const char*)z,"#breakpoint",11)==0 ) pik_breakpoint(z);
															         return i;
																     }
												     case '/': {
														             if( z[1]=='*' ){
																             for(i=2; z[i]!=0 && (z[i]!='*' || z[i+1]!='/'); i++){}
																	             if( z[i]=='*' ){
																			               pToken->eType = T_WHITESPACE;
																				                 return i+2;
																						         }else{
																								           pToken->eType = T_ERROR;
																									             return i;
																										             }
																		           }else if( z[1]=='/' ){
																				           for(i=2; z[i]!=0 && z[i]!='\n'; i++){}
																					           pToken->eType = T_WHITESPACE;
																						           return i;
																							         }else if( z[1]=='=' ){
																									         pToken->eType = T_ASSIGN;
																										         pToken->eCode = T_SLASH;
																											         return 2;
																												       }else{
																													               pToken->eType = T_SLASH;
																														               return 1;
																															             }
															         }
													           case '+': {
																           if( z[1]=='=' ){
																		           pToken->eType = T_ASSIGN;
																			           pToken->eCode = T_PLUS;
																				           return 2;
																					         }
																	         pToken->eType = T_PLUS;
																		       return 1;
																		           }
															         case '*': {
																		         if( z[1]=='=' ){
																				         pToken->eType = T_ASSIGN;
																					         pToken->eCode = T_STAR;
																						         return 2;
																							       }
																			       pToken->eType = T_STAR;
																			             return 1;
																				         }
																	       case '%': {   pToken->eType = T_PERCENT; return 1; }
																			     case '(': {   pToken->eType = T_LP;      return 1; }
																				           case ')': {   pToken->eType = T_RP;      return 1; }
																						         case '[': {   pToken->eType = T_LB;      return 1; }
																								       case ']': {   pToken->eType = T_RB;      return 1; }
																										     case ',': {   pToken->eType = T_COMMA;   return 1; }
																											           case ':': {   pToken->eType = T_COLON;   return 1; }
																													         case '>': {   pToken->eType = T_GT;      return 1; }
																															       case '=': {
																																		        if( z[1]=='=' ){
																																				         pToken->eType = T_EQ;
																																					          return 2;
																																						         }
																																			       pToken->eType = T_ASSIGN;
																																			              pToken->eCode = T_ASSIGN;
																																				             return 1;
																																					         }
																															       case '-': {
																																		       if( z[1]=='>' ){
																																			               pToken->eType = T_RARROW;
																																				               return 2;
																																					             }else if( z[1]=='=' ){
																																							             pToken->eType = T_ASSIGN;
																																								             pToken->eCode = T_MINUS;
																																									             return 2;
																																										           }else{
																																												           pToken->eType = T_MINUS;
																																													           return 1;
																																														         }
																																		           }
																																	     case '<': { 
																																			             if( z[1]=='-' ){
																																					              if( z[2]=='>' ){
																																							                 pToken->eType = T_LRARROW;
																																									            return 3;
																																										             }else{
																																												                pToken->eType = T_LARROW;
																																														           return 2;
																																															            }
																																						            }else{
																																								            pToken->eType = T_LT;
																																									            return 1;
																																										          }
																																				         }
																																		           case '{': {
																																					           int len, depth;
																																						         i = 1;
																																							       if( bAllowCodeBlock ){
																																								               depth = 1;
																																									               while( z[i] && depth>0 ){
																																											                 PToken x;
																																													           x.z = (char*)(z+i);
																																														             len = pik_token_length(&x, 0);
																																															               if( len==1 ){
																																																	                   if( z[i]=='{' ) depth++;
																																																			               if( z[i]=='}' ) depth--;
																																																				                 }
																																																                 i += len;
																																																		         }
																																										             }else{
																																												             depth = 0;
																																													           }
																																							             if( depth ){
																																									             pToken->eType = T_ERROR;
																																										             return 1;
																																											           }
																																								           pToken->eType = T_CODEBLOCK;
																																									         return i;
																																										     }
																																				         default: {
																																							        c = z[0];
																																								      if( c=='.' ){
																																									              unsigned char c1 = z[1];
																																										              if( islower(c1) ){
																																												                const PikWord *pFound;
																																														          for(i=2; (c = z[i])>='a' && c<='z'; i++){}
																																															            pFound = pik_find_word((const char*)z+1, i-1,
																																																		                                        pik_keywords, count(pik_keywords));
																																																              if( pFound && (pFound->eEdge>0 ||
																																																				                               pFound->eType==T_EDGEPT ||
																																																							                                pFound->eType==T_START ||
																																																											                         pFound->eType==T_END )
																																																			                ){
																																																		                  /* Dot followed by something that is a 2-D place value */
																																																		                  pToken->eType = T_DOT_E;
																																																				            }else if( pFound && (pFound->eType==T_X || pFound->eType==T_Y) ){
																																																						                /* Dot followed by "x" or "y" */
																																																						                pToken->eType = T_DOT_XY;
																																																								          }else{
																																																										              /* Any other "dot" */
																																																										              pToken->eType = T_DOT_L;
																																																											                }
																																																	                return 1;
																																																			        }else if( isdigit(c1) ){
																																																					          i = 0;
																																																						            /* no-op.  Fall through to number handling */
																																																						          }else if( isupper(c1) ){
																																																								            for(i=2; (c = z[i])!=0 && (isalnum(c) || c=='_'); i++){}
																																																									              pToken->eType = T_DOT_U;
																																																										                return 1;
																																																												        }else{
																																																														          pToken->eType = T_ERROR;
																																																															            return 1;
																																																																            }
																																											            }
																																								            if( (c>='0' && c<='9') || c=='.' ){
																																										            int nDigit;
																																											            int isInt = 1;
																																												            if( c!='.' ){
																																														              nDigit = 1;
																																															                for(i=1; (c = z[i])>='0' && c<='9'; i++){ nDigit++; }
																																																	          if( i==1 && (c=='x' || c=='X') ){
																																																			              for(i=2; (c = z[i])!=0 && isxdigit(c); i++){}
																																																				                  pToken->eType = T_NUMBER;
																																																						              return i;
																																																							                }
																																																		          }else{
																																																				            isInt = 0;
																																																					              nDigit = 0;
																																																						              }
																																													            if( c=='.' ){
																																															              isInt = 0;
																																																                for(i++; (c = z[i])>='0' && c<='9'; i++){ nDigit++; }
																																																		        }
																																														            if( nDigit==0 ){
																																																              pToken->eType = T_ERROR;
																																																	                return i;
																																																			        }
																																															            if( c=='e' || c=='E' ){
																																																	              int iBefore = i;
																																																		                i++;
																																																				          c2 = z[i];
																																																					            if( c2=='+' || c2=='-' ){
																																																							                i++;
																																																									            c2 = z[i];
																																																										              }
																																																						              if( c2<'0' || c>'9' ){
																																																								                  /* This is not an exp */
																																																								                  i = iBefore;
																																																										            }else{
																																																												                i++;
																																																														            isInt = 0;
																																																															                while( (c = z[i])>='0' && c<='9' ){ i++; }
																																																																	          }
																																																							              }
																																																            c2 = c ? z[i+1] : 0;
																																																	            if( isInt ){
																																																			              if( (c=='t' && c2=='h')
																																																						                 || (c=='r' && c2=='d')
																																																								            || (c=='n' && c2=='d')
																																																									               || (c=='s' && c2=='t')
																																																										                 ){
																																																					                  pToken->eType = T_NTH;
																																																							              return i+2;
																																																								                }
																																																				              }
																																																		            if( (c=='i' && c2=='n')
																																																					             || (c=='c' && c2=='m')
																																																						              || (c=='m' && c2=='m')
																																																							               || (c=='p' && c2=='t')
																																																								                || (c=='p' && c2=='x')
																																																										         || (c=='p' && c2=='c')
																																																											         ){
																																																				              i += 2;
																																																					              }
																																																			            pToken->eType = T_NUMBER;
																																																				            return i;
																																																					          }else if( islower(c) ){
																																																							          const PikWord *pFound;
																																																								          for(i=1; (c =  z[i])!=0 && (isalnum(c) || c=='_'); i++){}
																																																									          pFound = pik_find_word((const char*)z, i,
																																																												                                 pik_keywords, count(pik_keywords));
																																																										          if( pFound ){
																																																												            pToken->eType = pFound->eType;
																																																													              pToken->eCode = pFound->eCode;
																																																														                pToken->eEdge = pFound->eEdge;
																																																																          return i;
																																																																	          }
																																																											          pToken->n = i;
																																																												          if( pik_find_class(pToken)!=0 ){
																																																														            pToken->eType = T_CLASSNAME;
																																																															            }else{
																																																																	              pToken->eType = T_ID;
																																																																		              }
																																																													          return i;
																																																														        }else if( c>='A' && c<='Z' ){
																																																																        for(i=1; (c =  z[i])!=0 && (isalnum(c) || c=='_'); i++){}
																																																																	        pToken->eType = T_PLACENAME;
																																																																		        return i;
																																																																			      }else if( c=='$' && z[1]>='1' && z[1]<='9' && !isdigit(z[2]) ){
																																																																				              pToken->eType = T_PARAMETER;
																																																																					              pToken->eCode = z[1] - '1';
																																																																						              return 2;
																																																																							            }else if( c=='_' || c=='$' || c=='@' ){
																																																																									            for(i=1; (c =  z[i])!=0 && (isalnum(c) || c=='_'); i++){}
																																																																										            pToken->eType = T_ID;
																																																																											            return i;
																																																																												          }else{
																																																																														          pToken->eType = T_ERROR;
																																																																															          return 1;
																																																																																        }
																																									        }
																																						    }
}

/*
 * ** Return a pointer to the next non-whitespace token after pThis.
 * ** This is used to help form error messages.
 * */
static PToken pik_next_semantic_token(PToken *pThis){
	  PToken x;
	    int sz;
	      int i = pThis->n;
	        memset(&x, 0, sizeof(x));
		  x.z = pThis->z;
		    while(1){
			        x.z = pThis->z + i;
				    sz = pik_token_length(&x, 1);
				        if( x.eType!=T_WHITESPACE ){
						      x.n = sz;
						            return x;
							        }
					    i += sz;
					      }
}

/* Parser arguments to a macro invocation
 * **
 * **     (arg1, arg2, ...)
 * **
 * ** Arguments are comma-separated, except that commas within string
 * ** literals or with (...), {...}, or [...] do not count.  The argument
 * ** list begins and ends with parentheses.  There can be at most 9
 * ** arguments.
 * **
 * ** Return the number of bytes in the argument list.
 * */
static unsigned int pik_parse_macro_args(
		  Pik *p,
		    const char *z,     /* Start of the argument list */
		      int n,             /* Available bytes */
		        PToken *args
		){
	  int nArg = 0;
	    int i, sz;
	      int iStart;
	        int depth = 0;
		  PToken x;
		    if( z[0]!='(' ) return 0;
		      args[0].z = z+1;
		        iStart = 1;
			  for(i=1; i<n && z[i]!=')'; i+=sz){
				      x.z = z+i;
				          sz = pik_token_length(&x, 0);
					      if( sz!=1 ) continue;
					          if( z[i]==',' && depth<=0 ){
							        args[nArg].n = i - iStart;
								      if( nArg==8 ){
									              x.z = z;
										              x.n = 1;
											              pik_error(p, &x, "too many macro arguments - max 9");
												              return 0;
													            }
								            nArg++;
									          args[nArg].z = z+i+1;
										        iStart = i+1;
											      depth = 0;
											          }else if( z[i]=='(' || z[i]=='{' || z[i]=='[' ){
													        depth++;
														    }else if( z[i]==')' || z[i]=='}' || z[i]==']' ){
															          depth--;
																      }
						    }
			    if( z[i]==')' ){
				        args[nArg].n = i - iStart;
					    return i+1;
					      }
			      x.z = z;
			        x.n = 1;
				  pik_error(p, &x, "unterminated macro argument list");
				    return 0;
}

/*
 * ** Split up the content of a PToken into multiple tokens and
 * ** send each to the parser.
 * */
void pik_tokenize(Pik *p, PToken *pIn, yyParser *pParser, PToken *aParam){
	  unsigned int i;
	    int sz = 0;
	      PToken token;
	        PMacro *pMac;
		  for(i=0; i<pIn->n && pIn->z[i] && p->nErr==0; i+=sz){
			      token.eCode = 0;
			          token.eEdge = 0;
				      token.z = pIn->z + i;
				          sz = pik_token_length(&token, 1);
					      if( token.eType==T_WHITESPACE ){
						            /* no-op */
						          }else if( sz>1000 ){
								        token.n = 1;
									      pik_error(p, &token, "token is too long - max length 1000 bytes");
									            break;
										        }else if( token.eType==T_ERROR ){
												      token.n = (unsigned short)(sz & 0xffff);
												            pik_error(p, &token, "unrecognized token");
													          break;
														      }else if( sz+i>pIn->n ){
															            token.n = pIn->n - i;
																          pik_error(p, &token, "syntax error");
																	        break;
																		    }else if( token.eType==T_PARAMETER ){
																			          /* Substitute a parameter into the input stream */
																			          if( aParam==0 || aParam[token.eCode].n==0 ){
																					          continue;
																						        }
																				        token.n = (unsigned short)(sz & 0xffff);
																					      if( p->nCtx>=count(p->aCtx) ){
																						              pik_error(p, &token, "macros nested too deep");
																							            }else{
																									            p->aCtx[p->nCtx++] = token;
																										            pik_tokenize(p, &aParam[token.eCode], pParser, 0);
																											            p->nCtx--;
																												          }
																					          }else if( token.eType==T_ID && (pMac = pik_find_macro(p,&token))!=0 ){
																							        PToken args[9];
																								      unsigned int j = i+sz;
																								            if( pMac->inUse ){
																										            pik_error(p, &pMac->macroName, "recursive macro definition");
																											            break;
																												          }
																									          token.n = (short int)(sz & 0xffff);
																										        if( p->nCtx>=count(p->aCtx) ){
																												        pik_error(p, &token, "macros nested too deep");
																													        break;
																														      } 
																											      pMac->inUse = 1;
																											            memset(args, 0, sizeof(args));
																												          p->aCtx[p->nCtx++] = token;
																													        sz += pik_parse_macro_args(p, pIn->z+j, pIn->n-j, args);
																														      pik_tokenize(p, &pMac->macroBody, pParser, args);
																														            p->nCtx--;
																															          pMac->inUse = 0;
																																      }else{
#if 0
																																	            printf("******** Token %s (%d): \"%.*s\" **************\n",
																																				                 yyTokenName[token.eType], token.eType,
																																						              (int)(isspace(token.z[0]) ? 0 : sz), token.z);
#endif
																																		          token.n = (unsigned short)(sz & 0xffff);
																																			        pik_parser(pParser, token.eType, token);
																																				    }
					        }
}

/*
 * ** Parse the PIKCHR script contained in zText[].  Return a rendering.  Or
 * ** if an error is encountered, return the error text.  The error message
 * ** is HTML formatted.  So regardless of what happens, the return text
 * ** is safe to be insertd into an HTML output stream.
 * **
 * ** If pnWidth and pnHeight are not NULL, then this routine writes the
 * ** width and height of the <SVG> object into the integers that they
 * ** point to.  A value of -1 is written if an error is seen.
 * **
 * ** If zClass is not NULL, then it is a class name to be included in
 * ** the <SVG> markup.
 * **
 * ** The returned string is contained in memory obtained from malloc()
 * ** and should be released by the caller.
 * */
char *pikchr(
		  const char *zText,     /* Input PIKCHR source text.  zero-terminated */
		    const char *zClass,    /* Add class="%s" to <svg> markup */
		      unsigned int mFlags,   /* Flags used to influence rendering behavior */
		        int *pnWidth,          /* Write width of <svg> here, if not NULL */
			  int *pnHeight          /* Write height here, if not NULL */
	    ){
	  Pik s;
	    yyParser sParse;

	      memset(&s, 0, sizeof(s));
	        s.sIn.z = zText;
		  s.sIn.n = (unsigned int)strlen(zText);
		    s.eDir = DIR_RIGHT;
		      s.zClass = zClass;
		        s.mFlags = mFlags;
			  pik_parserInit(&sParse, &s);
#if 0
			    pik_parserTrace(stdout, "parser: ");
#endif
			      pik_tokenize(&s, &s.sIn, &sParse, 0);
			        if( s.nErr==0 ){
					    PToken token;
					        memset(&token,0,sizeof(token));
						    token.z = zText;
						        pik_parser(&sParse, 0, token);
							  }
				  pik_parserFinalize(&sParse);
				    if( s.zOut==0 && s.nErr==0 ){
					        pik_append(&s, "<!-- empty pikchr diagram -->\n", -1);
						  }
				      while( s.pVar ){
					          PVar *pNext = s.pVar->pNext;
						      free(s.pVar);
						          s.pVar = pNext;
							    }
				        while( s.pMacros ){
						    PMacro *pNext = s.pMacros->pNext;
						        free(s.pMacros);
							    s.pMacros = pNext;
							      }
					  if( pnWidth ) *pnWidth = s.nErr ? -1 : s.wSVG;
					    if( pnHeight ) *pnHeight = s.nErr ? -1 : s.hSVG;
					      if( s.zOut ){
						          s.zOut[s.nOut] = 0;
							      s.zOut = realloc(s.zOut, s.nOut+1);
							        }
					        return s.zOut;
}

#if defined(PIKCHR_FUZZ)
#include <stdint.h>
int LLVMFuzzerTestOneInput(const uint8_t *aData, size_t nByte){
	  int w,h;
	    char *zIn, *zOut;
	      zIn = malloc( nByte + 1 );
	        if( zIn==0 ) return 0;
		  memcpy(zIn, aData, nByte);
		    zIn[nByte] = 0;
		      zOut = pikchr(zIn, "pikchr", 0, &w, &h);
		        free(zIn);
			  free(zOut);
			    return 0;
}
#endif /* PIKCHR_FUZZ */

#if defined(PIKCHR_SHELL)
/* Print a usage comment for the shell and exit. */
static void usage(const char *argv0){
	  fprintf(stderr, "usage: %s [OPTIONS] FILE ...\n", argv0);
	    fprintf(stderr,
			        "Convert Pikchr input files into SVG.\n"
				    "Options:\n"
				        "   --dont-stop      Process all files even if earlier files have errors\n"
					    "   --svg-only       Omit raw SVG without the HTML wrapper\n"
					      );
	      exit(1);
}

/* Send text to standard output, but escape HTML markup */
static void print_escape_html(const char *z){
	  int j;
	    char c;
	      while( z[0]!=0 ){
		          for(j=0; (c = z[j])!=0 && c!='<' && c!='>' && c!='&'; j++){}
			      if( j ) printf("%.*s", j, z);
			          z += j+1;
				      j = -1;
				          if( c=='<' ){
						        printf("&lt;");
							    }else if( c=='>' ){
								          printf("&gt;");
									      }else if( c=='&' ){
										            printf("&amp;");
											        }else if( c==0 ){
													      break;
													          }
					    }
}

/* Testing interface
 * **
 * ** Generate HTML on standard output that displays both the original
 * ** input text and the rendered SVG for all files named on the command
 * ** line.
 * */
int main(int argc, char **argv){
	  int i;
	    int bSvgOnly = 0;            /* Output SVG only.  No HTML wrapper */
	      int bDontStop = 0;           /* Continue in spite of errors */
	        const char *zHtmlHdr = 
			    "<!DOCTYPE html>\n"
			        "<html lang=\"en-US\">\n"
				    "<head>\n<title>PIKCHR Test</title>\n"
				        "<style>\n"
					    "  .hidden {\n"
					        "     position: absolute !important;\n"
						    "     opacity: 0 !important;\n"
						        "     pointer-events: none !important;\n"
							    "     display: none !important;\n"
							        "  }\n"
								    "</style>\n"
								        "<script>\n"
									    "  function toggleHidden(id){\n"
									        "    for(var c of document.getElementById(id).children){\n"
										    "      c.classList.toggle('hidden');\n"
										        "    }\n"
											    "  }\n"
											        "</script>\n"
												    "<meta charset=\"utf-8\">\n"
												        "</head>\n"
													    "<body>\n"
													      ;
		  if( argc<2 ) usage(argv[0]);
		    for(i=1; i<argc; i++){
			        FILE *in;
				    size_t sz;
				        char *zIn;
					    char *zOut;
					        int w, h;

						    if( argv[i][0]=='-' ){
							          char *z = argv[i];
								        z++;
									      if( z[0]=='-' ) z++;
									            if( strcmp(z,"dont-stop")==0 ){
											            bDontStop = 1;
												          }else
														        if( strcmp(z,"svg-only")==0 ){
																        if( zHtmlHdr==0 ){
																		          fprintf(stderr, "the \"%s\" option must come first\n",argv[i]);
																			            exit(1);
																				            }
																	        bSvgOnly = 1;
																		      }else
																			            {
																					            fprintf(stderr,"unknown option: \"%s\"\n", argv[i]);
																						            usage(argv[0]);
																							          }
													        continue;
														    }
						        in = fopen(argv[i], "rb");
							    if( in==0 ){
								          fprintf(stderr, "cannot open \"%s\" for reading\n", argv[i]);
									        continue;
										    }
							        fseek(in, 0, SEEK_END);
								    sz = ftell(in);
								        rewind(in);
									    zIn = malloc( sz+1 );
									        if( zIn==0 ){
											      fprintf(stderr, "cannot allocate space for file \"%s\"\n", argv[i]);
											            fclose(in);
												          continue;
													      }
										    sz = fread(zIn, 1, sz, in);
										        fclose(in);
											    zIn[sz] = 0;
											        zOut = pikchr(zIn, "pikchr", 0, &w, &h);
												    if( zOut==0 ){
													          fprintf(stderr, "pikchr() returns NULL.  Out of memory?\n");
														        if( !bDontStop ) exit(1);
															    }else if( bSvgOnly ){
																          printf("%s\n", zOut);
																	      }else{
																		            if( zHtmlHdr ){
																				            printf("%s", zHtmlHdr);
																					            zHtmlHdr = 0;
																						          }
																			          printf("<h1>File %s</h1>\n", argv[i]);
																				        if( w<0 ){
																						        printf("<p>ERROR</p>\n%s\n", zOut);
																							      }else{
																								              printf("<div id=\"svg-%d\" onclick=\"toggleHidden('svg-%d')\">\n",i,i);
																									              printf("<div style='border:3px solid lightgray;max-width:%dpx;'>\n",w);
																										              printf("%s</div>\n", zOut);
																											              printf("<pre class='hidden'>");
																												              print_escape_html(zIn);
																													              printf("</pre>\n</div>\n");
																														            }
																					    }
												        free(zOut);
													    free(zIn);
													      }
		      if( !bSvgOnly ){
			          printf("</body></html>\n");
				    }
		        return 0; 
}
#endif /* PIKCHR_SHELL */

#line 7626 "pikchr.c"

