|
1
|
/* This file is automatically generated by Lemon from input grammar |
|
2
|
** source file "pikchr.y". |
|
3
|
*/ |
|
4
|
/* |
|
5
|
** 2000-05-29 |
|
6
|
** |
|
7
|
** The author disclaims copyright to this source code. In place of |
|
8
|
** a legal notice, here is a blessing: |
|
9
|
** |
|
10
|
** May you do good and not evil. |
|
11
|
** May you find forgiveness for yourself and forgive others. |
|
12
|
** May you share freely, never taking more than you give. |
|
13
|
** |
|
14
|
************************************************************************* |
|
15
|
** Driver template for the LEMON parser generator. |
|
16
|
** |
|
17
|
** The "lemon" program processes an LALR(1) input grammar file, then uses |
|
18
|
** this template to construct a parser. The "lemon" program inserts text |
|
19
|
** at each "%%" line. Also, any "P-a-r-s-e" identifier prefix (without the |
|
20
|
** interstitial "-" characters) contained in this template is changed into |
|
21
|
** the value of the %name directive from the grammar. Otherwise, the content |
|
22
|
** of this template is copied straight through into the generate parser |
|
23
|
** source file. |
|
24
|
** |
|
25
|
** The following is the concatenation of all %include directives from the |
|
26
|
** input grammar file: |
|
27
|
*/ |
|
28
|
/************ Begin %include sections from the grammar ************************/ |
|
29
|
#line 1 "VERSION.h" |
|
30
|
#define MANIFEST_UUID "a7f1c35bc0448daf15e2bafa36e510c1517534e620c452ecb314ed57d974f081" |
|
31
|
#define MANIFEST_VERSION "[a7f1c35bc0]" |
|
32
|
#define MANIFEST_DATE "2026-04-03 10:29:56" |
|
33
|
#define MANIFEST_YEAR "2026" |
|
34
|
#define MANIFEST_ISODATE "20260403102956" |
|
35
|
#define MANIFEST_NUMERIC_DATE 20260403 |
|
36
|
#define MANIFEST_NUMERIC_TIME 102956 |
|
37
|
#define RELEASE_VERSION "1.0" |
|
38
|
#define RELEASE_VERSION_NUMBER 10000 |
|
39
|
#define RELEASE_RESOURCE_VERSION 1,0,0,0 |
|
40
|
#define COMPILER "gcc-13.3.0" |
|
41
|
#line 2 "pikchr.y" |
|
42
|
|
|
43
|
/* |
|
44
|
** Zero-Clause BSD license: |
|
45
|
** |
|
46
|
** Copyright (C) 2020-09-01 by D. Richard Hipp <[email protected]> |
|
47
|
** |
|
48
|
** Permission to use, copy, modify, and/or distribute this software for |
|
49
|
** any purpose with or without fee is hereby granted. |
|
50
|
** |
|
51
|
**************************************************************************** |
|
52
|
** |
|
53
|
** This software translates a PIC-inspired diagram language into SVG. |
|
54
|
** |
|
55
|
** PIKCHR (pronounced like "picture") is *mostly* backwards compatible |
|
56
|
** with legacy PIC, though some features of legacy PIC are removed |
|
57
|
** (for example, the "sh" command is removed for security) and |
|
58
|
** many enhancements are added. |
|
59
|
** |
|
60
|
** PIKCHR is designed for use in an internet facing web environment. |
|
61
|
** In particular, PIKCHR is designed to safely generate benign SVG from |
|
62
|
** source text that provided by a hostile agent. |
|
63
|
** |
|
64
|
** This code was originally written by D. Richard Hipp using documentation |
|
65
|
** from prior PIC implementations but without reference to prior code. |
|
66
|
** All of the code in this project is original. |
|
67
|
** |
|
68
|
** This file implements a C-language subroutine that accepts a string |
|
69
|
** of PIKCHR language text and generates a second string of SVG output that |
|
70
|
** renders the drawing defined by the input. Space to hold the returned |
|
71
|
** string is obtained from malloc() and should be freed by the caller. |
|
72
|
** NULL might be returned if there is a memory allocation error. |
|
73
|
** |
|
74
|
** If there are errors in the PIKCHR input, the output will consist of an |
|
75
|
** error message and the original PIKCHR input text (inside of <pre>...</pre>). |
|
76
|
** |
|
77
|
** The subroutine implemented by this file is intended to be stand-alone. |
|
78
|
** It uses no external routines other than routines commonly found in |
|
79
|
** the standard C library. |
|
80
|
** |
|
81
|
**************************************************************************** |
|
82
|
** COMPILING: |
|
83
|
** |
|
84
|
** The original source text is a mixture of C99 and "Lemon" |
|
85
|
** (See https://sqlite.org/src/file/doc/lemon.html). Lemon is an LALR(1) |
|
86
|
** parser generator program, similar to Yacc. The grammar of the |
|
87
|
** input language is specified in Lemon. C-code is attached. Lemon |
|
88
|
** runs to generate a single output file ("pikchr.c") which is then |
|
89
|
** compiled to generate the Pikchr library. This header comment is |
|
90
|
** preserved in the Lemon output, so you might be reading this in either |
|
91
|
** the generated "pikchr.c" file that is output by Lemon, or in the |
|
92
|
** "pikchr.y" source file that is input into Lemon. If you make changes, |
|
93
|
** you should change the input source file "pikchr.y", not the |
|
94
|
** Lemon-generated output file. |
|
95
|
** |
|
96
|
** Basic compilation steps: |
|
97
|
** |
|
98
|
** lemon pikchr.y |
|
99
|
** cc pikchr.c -o pikchr.o |
|
100
|
** |
|
101
|
** Add -DPIKCHR_SHELL to add a main() routine that reads input files |
|
102
|
** and sends them through Pikchr, for testing. Add -DPIKCHR_FUZZ for |
|
103
|
** -fsanitizer=fuzzer testing. |
|
104
|
** |
|
105
|
**************************************************************************** |
|
106
|
** IMPLEMENTATION NOTES (for people who want to understand the internal |
|
107
|
** operation of this software, perhaps to extend the code or to fix bugs): |
|
108
|
** |
|
109
|
** Each call to pikchr() uses a single instance of the Pik structure to |
|
110
|
** track its internal state. The Pik structure lives for the duration |
|
111
|
** of the pikchr() call. |
|
112
|
** |
|
113
|
** The input is a sequence of objects or "statements". Each statement is |
|
114
|
** parsed into a PObj object. These are stored on an extensible array |
|
115
|
** called PList. All parameters to each PObj are computed as the |
|
116
|
** object is parsed. (Hence, the parameters to a PObj may only refer |
|
117
|
** to prior statements.) Once the PObj is completely assembled, it is |
|
118
|
** added to the end of a PList and never changes thereafter - except, |
|
119
|
** PObj objects that are part of a "[...]" block might have their |
|
120
|
** absolute position shifted when the outer [...] block is positioned. |
|
121
|
** But apart from this repositioning, PObj objects are unchanged once |
|
122
|
** they are added to the list. The order of statements on a PList does |
|
123
|
** not change. |
|
124
|
** |
|
125
|
** After all input has been parsed, the top-level PList is walked to |
|
126
|
** generate output. Sub-lists resulting from [...] blocks are scanned |
|
127
|
** as they are encountered. All input must be collected and parsed ahead |
|
128
|
** of output generation because the size and position of statements must be |
|
129
|
** known in order to compute a bounding box on the output. |
|
130
|
** |
|
131
|
** Each PObj is on a "layer". (The common case is that all PObj's are |
|
132
|
** on a single layer, but multiple layers are possible.) A separate pass |
|
133
|
** is made through the list for each layer. |
|
134
|
** |
|
135
|
** After all output is generated, the Pik object and all the PList |
|
136
|
** and PObj objects are deallocated and the generated output string is |
|
137
|
** returned. Upon any error, the Pik.nErr flag is set, processing quickly |
|
138
|
** stops, and the stack unwinds. No attempt is made to continue reading |
|
139
|
** input after an error. |
|
140
|
** |
|
141
|
** Most statements begin with a class name like "box" or "arrow" or "move". |
|
142
|
** There is a class named "text" which is used for statements that begin |
|
143
|
** with a string literal. You can also specify the "text" class. |
|
144
|
** A Sublist ("[...]") is a single object that contains a pointer to |
|
145
|
** its substatements, all gathered onto a separate PList object. |
|
146
|
** |
|
147
|
** Variables go into PVar objects that form a linked list. |
|
148
|
** |
|
149
|
** Each PObj has zero or one names. Input constructs that attempt |
|
150
|
** to assign a new name from an older name, for example: |
|
151
|
** |
|
152
|
** Abc: Abc + (0.5cm, 0) |
|
153
|
** |
|
154
|
** Statements like these generate a new "noop" object at the specified |
|
155
|
** place and with the given name. As place-names are searched by scanning |
|
156
|
** the list in reverse order, this has the effect of overriding the "Abc" |
|
157
|
** name when referenced by subsequent objects. |
|
158
|
*/ |
|
159
|
#include <stdio.h> |
|
160
|
#include <stdlib.h> |
|
161
|
#include <string.h> |
|
162
|
#include <ctype.h> |
|
163
|
#include <math.h> |
|
164
|
#include <assert.h> |
|
165
|
#define count(X) (sizeof(X)/sizeof(X[0])) |
|
166
|
#ifndef M_PI |
|
167
|
# define M_PI 3.1415926535897932385 |
|
168
|
#endif |
|
169
|
|
|
170
|
/* |
|
171
|
** Typesafe version of ctype.h macros. Cygwin requires this, I'm told. |
|
172
|
*/ |
|
173
|
#define IsUpper(X) isupper((unsigned char)(X)) |
|
174
|
#define IsLower(X) islower((unsigned char)(X)) |
|
175
|
#define ToLower(X) tolower((unsigned char)(X)) |
|
176
|
#define IsDigit(X) isdigit((unsigned char)(X)) |
|
177
|
#define IsXDigit(X) isxdigit((unsigned char)(X)) |
|
178
|
#define IsSpace(X) isspace((unsigned char)(X)) |
|
179
|
#define IsAlnum(X) isalnum((unsigned char)(X)) |
|
180
|
|
|
181
|
|
|
182
|
/* Limit the number of tokens in a single script to avoid run-away |
|
183
|
** macro expansion attacks. See forum post |
|
184
|
** https://pikchr.org/home/forumpost/ef8684c6955a411a |
|
185
|
*/ |
|
186
|
#ifndef PIKCHR_TOKEN_LIMIT |
|
187
|
# define PIKCHR_TOKEN_LIMIT 100000 |
|
188
|
#endif |
|
189
|
|
|
190
|
|
|
191
|
/* Tag intentionally unused parameters with this macro to prevent |
|
192
|
** compiler warnings with -Wextra */ |
|
193
|
#define UNUSED_PARAMETER(X) (void)(X) |
|
194
|
|
|
195
|
typedef struct Pik Pik; /* Complete parsing context */ |
|
196
|
typedef struct PToken PToken; /* A single token */ |
|
197
|
typedef struct PObj PObj; /* A single diagram object */ |
|
198
|
typedef struct PList PList; /* A list of diagram objects */ |
|
199
|
typedef struct PClass PClass; /* Description of statements types */ |
|
200
|
typedef double PNum; /* Numeric value */ |
|
201
|
typedef struct PRel PRel; /* Absolute or percentage value */ |
|
202
|
typedef struct PPoint PPoint; /* A position in 2-D space */ |
|
203
|
typedef struct PVar PVar; /* script-defined variable */ |
|
204
|
typedef struct PBox PBox; /* A bounding box */ |
|
205
|
typedef struct PMacro PMacro; /* A "define" macro */ |
|
206
|
|
|
207
|
/* Compass points */ |
|
208
|
#define CP_N 1 |
|
209
|
#define CP_NE 2 |
|
210
|
#define CP_E 3 |
|
211
|
#define CP_SE 4 |
|
212
|
#define CP_S 5 |
|
213
|
#define CP_SW 6 |
|
214
|
#define CP_W 7 |
|
215
|
#define CP_NW 8 |
|
216
|
#define CP_C 9 /* .center or .c */ |
|
217
|
#define CP_END 10 /* .end */ |
|
218
|
#define CP_START 11 /* .start */ |
|
219
|
|
|
220
|
/* Heading angles corresponding to compass points */ |
|
221
|
static const PNum pik_hdg_angle[] = { |
|
222
|
/* none */ 0.0, |
|
223
|
/* N */ 0.0, |
|
224
|
/* NE */ 45.0, |
|
225
|
/* E */ 90.0, |
|
226
|
/* SE */ 135.0, |
|
227
|
/* S */ 180.0, |
|
228
|
/* SW */ 225.0, |
|
229
|
/* W */ 270.0, |
|
230
|
/* NW */ 315.0, |
|
231
|
/* C */ 0.0, |
|
232
|
}; |
|
233
|
|
|
234
|
/* Built-in functions */ |
|
235
|
#define FN_ABS 0 |
|
236
|
#define FN_COS 1 |
|
237
|
#define FN_INT 2 |
|
238
|
#define FN_MAX 3 |
|
239
|
#define FN_MIN 4 |
|
240
|
#define FN_SIN 5 |
|
241
|
#define FN_SQRT 6 |
|
242
|
|
|
243
|
/* Text position and style flags. Stored in PToken.eCode so limited |
|
244
|
** to 15 bits. */ |
|
245
|
#define TP_LJUST 0x0001 /* left justify...... */ |
|
246
|
#define TP_RJUST 0x0002 /* ...Right justify */ |
|
247
|
#define TP_JMASK 0x0003 /* Mask for justification bits */ |
|
248
|
#define TP_ABOVE2 0x0004 /* Position text way above PObj.ptAt */ |
|
249
|
#define TP_ABOVE 0x0008 /* Position text above PObj.ptAt */ |
|
250
|
#define TP_CENTER 0x0010 /* On the line */ |
|
251
|
#define TP_BELOW 0x0020 /* Position text below PObj.ptAt */ |
|
252
|
#define TP_BELOW2 0x0040 /* Position text way below PObj.ptAt */ |
|
253
|
#define TP_VMASK 0x007c /* Mask for text positioning flags */ |
|
254
|
#define TP_BIG 0x0100 /* Larger font */ |
|
255
|
#define TP_SMALL 0x0200 /* Smaller font */ |
|
256
|
#define TP_XTRA 0x0400 /* Amplify TP_BIG or TP_SMALL */ |
|
257
|
#define TP_SZMASK 0x0700 /* Font size mask */ |
|
258
|
#define TP_ITALIC 0x1000 /* Italic font */ |
|
259
|
#define TP_BOLD 0x2000 /* Bold font */ |
|
260
|
#define TP_MONO 0x4000 /* Monospace font family */ |
|
261
|
#define TP_FMASK 0x7000 /* Mask for font style */ |
|
262
|
#define TP_ALIGN 0x8000 /* Rotate to align with the line */ |
|
263
|
|
|
264
|
/* An object to hold a position in 2-D space */ |
|
265
|
struct PPoint { |
|
266
|
PNum x, y; /* X and Y coordinates */ |
|
267
|
}; |
|
268
|
static const PPoint cZeroPoint = {0.0,0.0}; |
|
269
|
|
|
270
|
/* A bounding box */ |
|
271
|
struct PBox { |
|
272
|
PPoint sw, ne; /* Lower-left and top-right corners */ |
|
273
|
}; |
|
274
|
|
|
275
|
/* An Absolute or a relative distance. The absolute distance |
|
276
|
** is stored in rAbs and the relative distance is stored in rRel. |
|
277
|
** Usually, one or the other will be 0.0. When using a PRel to |
|
278
|
** update an existing value, the computation is usually something |
|
279
|
** like this: |
|
280
|
** |
|
281
|
** value = PRel.rAbs + value*PRel.rRel |
|
282
|
** |
|
283
|
*/ |
|
284
|
struct PRel { |
|
285
|
PNum rAbs; /* Absolute value */ |
|
286
|
PNum rRel; /* Value relative to current value */ |
|
287
|
}; |
|
288
|
|
|
289
|
/* A variable created by the ID = EXPR construct of the PIKCHR script |
|
290
|
** |
|
291
|
** PIKCHR (and PIC) scripts do not use many varaibles, so it is reasonable |
|
292
|
** to store them all on a linked list. |
|
293
|
*/ |
|
294
|
struct PVar { |
|
295
|
const char *zName; /* Name of the variable */ |
|
296
|
PNum val; /* Value of the variable */ |
|
297
|
PVar *pNext; /* Next variable in a list of them all */ |
|
298
|
}; |
|
299
|
|
|
300
|
/* A single token in the parser input stream |
|
301
|
*/ |
|
302
|
struct PToken { |
|
303
|
const char *z; /* Pointer to the token text */ |
|
304
|
unsigned int n; /* Length of the token in bytes */ |
|
305
|
short int eCode; /* Auxiliary code */ |
|
306
|
unsigned char eType; /* The numeric parser code */ |
|
307
|
unsigned char eEdge; /* Corner value for corner keywords */ |
|
308
|
}; |
|
309
|
|
|
310
|
/* Return negative, zero, or positive if pToken is less than, equal to |
|
311
|
** or greater than the zero-terminated string z[] |
|
312
|
*/ |
|
313
|
static int pik_token_eq(PToken *pToken, const char *z){ |
|
314
|
int c = strncmp(pToken->z,z,pToken->n); |
|
315
|
if( c==0 && z[pToken->n]!=0 ) c = -1; |
|
316
|
return c; |
|
317
|
} |
|
318
|
|
|
319
|
/* Extra token types not generated by LEMON but needed by the |
|
320
|
** tokenizer |
|
321
|
*/ |
|
322
|
#define T_PARAMETER 253 /* $1, $2, ..., $9 */ |
|
323
|
#define T_WHITESPACE 254 /* Whitespace or comments */ |
|
324
|
#define T_ERROR 255 /* Any text that is not a valid token */ |
|
325
|
|
|
326
|
/* Directions of movement */ |
|
327
|
#define DIR_RIGHT 0 |
|
328
|
#define DIR_DOWN 1 |
|
329
|
#define DIR_LEFT 2 |
|
330
|
#define DIR_UP 3 |
|
331
|
#define ValidDir(X) ((X)>=0 && (X)<=3) |
|
332
|
#define IsUpDown(X) (((X)&1)==1) |
|
333
|
#define IsLeftRight(X) (((X)&1)==0) |
|
334
|
|
|
335
|
/* Bitmask for the various attributes for PObj. These bits are |
|
336
|
** collected in PObj.mProp and PObj.mCalc to check for constraint |
|
337
|
** errors. */ |
|
338
|
#define A_WIDTH 0x0001 |
|
339
|
#define A_HEIGHT 0x0002 |
|
340
|
#define A_RADIUS 0x0004 |
|
341
|
#define A_THICKNESS 0x0008 |
|
342
|
#define A_DASHED 0x0010 /* Includes "dotted" */ |
|
343
|
#define A_FILL 0x0020 |
|
344
|
#define A_COLOR 0x0040 |
|
345
|
#define A_ARROW 0x0080 |
|
346
|
#define A_FROM 0x0100 |
|
347
|
#define A_CW 0x0200 |
|
348
|
#define A_AT 0x0400 |
|
349
|
#define A_TO 0x0800 /* one or more movement attributes */ |
|
350
|
#define A_FIT 0x1000 |
|
351
|
|
|
352
|
|
|
353
|
/* A single graphics object */ |
|
354
|
struct PObj { |
|
355
|
const PClass *type; /* Object type or class */ |
|
356
|
PToken errTok; /* Reference token for error messages */ |
|
357
|
PPoint ptAt; /* Reference point for the object */ |
|
358
|
PPoint ptEnter, ptExit; /* Entry and exit points */ |
|
359
|
PList *pSublist; /* Substructure for [...] objects */ |
|
360
|
char *zName; /* Name assigned to this statement */ |
|
361
|
PNum w; /* "width" property */ |
|
362
|
PNum h; /* "height" property */ |
|
363
|
PNum rad; /* "radius" property */ |
|
364
|
PNum sw; /* "thickness" property. (Mnemonic: "stroke width")*/ |
|
365
|
PNum dotted; /* "dotted" property. <=0.0 for off */ |
|
366
|
PNum dashed; /* "dashed" property. <=0.0 for off */ |
|
367
|
PNum fill; /* "fill" property. Negative for off */ |
|
368
|
PNum color; /* "color" property */ |
|
369
|
PPoint with; /* Position constraint from WITH clause */ |
|
370
|
char eWith; /* Type of heading point on WITH clause */ |
|
371
|
char cw; /* True for clockwise arc */ |
|
372
|
char larrow; /* Arrow at beginning (<- or <->) */ |
|
373
|
char rarrow; /* Arrow at end (-> or <->) */ |
|
374
|
char bClose; /* True if "close" is seen */ |
|
375
|
char bChop; /* True if "chop" is seen */ |
|
376
|
char bAltAutoFit; /* Always send both h and w into xFit() */ |
|
377
|
unsigned char nTxt; /* Number of text values */ |
|
378
|
unsigned mProp; /* Masks of properties set so far */ |
|
379
|
unsigned mCalc; /* Values computed from other constraints */ |
|
380
|
PToken aTxt[5]; /* Text with .eCode holding TP flags */ |
|
381
|
int iLayer; /* Rendering order */ |
|
382
|
int inDir, outDir; /* Entry and exit directions */ |
|
383
|
int nPath; /* Number of path points */ |
|
384
|
PPoint *aPath; /* Array of path points */ |
|
385
|
PObj *pFrom, *pTo; /* End-point objects of a path */ |
|
386
|
PBox bbox; /* Bounding box */ |
|
387
|
}; |
|
388
|
|
|
389
|
/* A list of graphics objects */ |
|
390
|
struct PList { |
|
391
|
int n; /* Number of statements in the list */ |
|
392
|
int nAlloc; /* Allocated slots in a[] */ |
|
393
|
PObj **a; /* Pointers to individual objects */ |
|
394
|
}; |
|
395
|
|
|
396
|
/* A macro definition */ |
|
397
|
struct PMacro { |
|
398
|
PMacro *pNext; /* Next in the list */ |
|
399
|
PToken macroName; /* Name of the macro */ |
|
400
|
PToken macroBody; /* Body of the macro */ |
|
401
|
int inUse; /* Do not allow recursion */ |
|
402
|
}; |
|
403
|
|
|
404
|
/* Each call to the pikchr() subroutine uses an instance of the following |
|
405
|
** object to pass around context to all of its subroutines. |
|
406
|
*/ |
|
407
|
struct Pik { |
|
408
|
unsigned nErr; /* Number of errors seen */ |
|
409
|
unsigned nToken; /* Number of tokens parsed */ |
|
410
|
PToken sIn; /* Input Pikchr-language text */ |
|
411
|
char *zOut; /* Result accumulates here */ |
|
412
|
unsigned int nOut; /* Bytes written to zOut[] so far */ |
|
413
|
unsigned int nOutAlloc; /* Space allocated to zOut[] */ |
|
414
|
unsigned char eDir; /* Current direction */ |
|
415
|
unsigned int mFlags; /* Flags passed to pikchr() */ |
|
416
|
PObj *cur; /* Object under construction */ |
|
417
|
PObj *lastRef; /* Last object references by name */ |
|
418
|
PList *list; /* Object list under construction */ |
|
419
|
PMacro *pMacros; /* List of all defined macros */ |
|
420
|
PVar *pVar; /* Application-defined variables */ |
|
421
|
PBox bbox; /* Bounding box around all statements */ |
|
422
|
/* Cache of layout values. <=0.0 for unknown... */ |
|
423
|
PNum rScale; /* Multiply to convert inches to pixels */ |
|
424
|
PNum fontScale; /* Scale fonts by this percent */ |
|
425
|
PNum charWidth; /* Character width */ |
|
426
|
PNum charHeight; /* Character height */ |
|
427
|
PNum wArrow; /* Width of arrowhead at the fat end */ |
|
428
|
PNum hArrow; /* Ht of arrowhead - dist from tip to fat end */ |
|
429
|
char bLayoutVars; /* True if cache is valid */ |
|
430
|
char thenFlag; /* True if "then" seen */ |
|
431
|
char samePath; /* aTPath copied by "same" */ |
|
432
|
const char *zClass; /* Class name for the <svg> */ |
|
433
|
int wSVG, hSVG; /* Width and height of the <svg> */ |
|
434
|
int fgcolor; /* foreground color value, or -1 for none */ |
|
435
|
int bgcolor; /* background color value, or -1 for none */ |
|
436
|
/* Paths for lines are constructed here first, then transferred into |
|
437
|
** the PObj object at the end: */ |
|
438
|
int nTPath; /* Number of entries on aTPath[] */ |
|
439
|
int mTPath; /* For last entry, 1: x set, 2: y set */ |
|
440
|
PPoint aTPath[1000]; /* Path under construction */ |
|
441
|
/* Error contexts */ |
|
442
|
unsigned int nCtx; /* Number of error contexts */ |
|
443
|
PToken aCtx[10]; /* Nested error contexts */ |
|
444
|
}; |
|
445
|
|
|
446
|
/* Include PIKCHR_PLAINTEXT_ERRORS among the bits of mFlags on the 3rd |
|
447
|
** argument to pikchr() in order to cause error message text to come out |
|
448
|
** as text/plain instead of as text/html |
|
449
|
*/ |
|
450
|
#define PIKCHR_PLAINTEXT_ERRORS 0x0001 |
|
451
|
|
|
452
|
/* Include PIKCHR_DARK_MODE among the mFlag bits to invert colors. |
|
453
|
*/ |
|
454
|
#define PIKCHR_DARK_MODE 0x0002 |
|
455
|
|
|
456
|
/* |
|
457
|
** The behavior of an object class is defined by an instance of |
|
458
|
** this structure. This is the "virtual method" table. |
|
459
|
*/ |
|
460
|
struct PClass { |
|
461
|
const char *zName; /* Name of class */ |
|
462
|
char isLine; /* True if a line class */ |
|
463
|
char eJust; /* Use box-style text justification */ |
|
464
|
void (*xInit)(Pik*,PObj*); /* Initializer */ |
|
465
|
void (*xNumProp)(Pik*,PObj*,PToken*); /* Value change notification */ |
|
466
|
void (*xCheck)(Pik*,PObj*); /* Checks to do after parsing */ |
|
467
|
PPoint (*xChop)(Pik*,PObj*,PPoint*); /* Chopper */ |
|
468
|
PPoint (*xOffset)(Pik*,PObj*,int); /* Offset from .c to edge point */ |
|
469
|
void (*xFit)(Pik*,PObj*,PNum w,PNum h); /* Size to fit text */ |
|
470
|
void (*xRender)(Pik*,PObj*); /* Render */ |
|
471
|
}; |
|
472
|
|
|
473
|
|
|
474
|
/* Forward declarations */ |
|
475
|
static void pik_append(Pik*, const char*,int); |
|
476
|
static void pik_append_text(Pik*,const char*,int,int); |
|
477
|
static void pik_append_num(Pik*,const char*,PNum); |
|
478
|
static void pik_append_point(Pik*,const char*,PPoint*); |
|
479
|
static void pik_append_x(Pik*,const char*,PNum,const char*); |
|
480
|
static void pik_append_y(Pik*,const char*,PNum,const char*); |
|
481
|
static void pik_append_xy(Pik*,const char*,PNum,PNum); |
|
482
|
static void pik_append_dis(Pik*,const char*,PNum,const char*); |
|
483
|
static void pik_append_arc(Pik*,PNum,PNum,PNum,PNum); |
|
484
|
static void pik_append_clr(Pik*,const char*,PNum,const char*,int); |
|
485
|
static void pik_append_style(Pik*,PObj*,int); |
|
486
|
static void pik_append_txt(Pik*,PObj*, PBox*); |
|
487
|
static void pik_draw_arrowhead(Pik*,PPoint*pFrom,PPoint*pTo,PObj*); |
|
488
|
static void pik_chop(PPoint*pFrom,PPoint*pTo,PNum); |
|
489
|
static void pik_error(Pik*,PToken*,const char*); |
|
490
|
static void pik_elist_free(Pik*,PList*); |
|
491
|
static void pik_elem_free(Pik*,PObj*); |
|
492
|
static void pik_render(Pik*,PList*); |
|
493
|
static PList *pik_elist_append(Pik*,PList*,PObj*); |
|
494
|
static PObj *pik_elem_new(Pik*,PToken*,PToken*,PList*); |
|
495
|
static void pik_set_direction(Pik*,int); |
|
496
|
static void pik_elem_setname(Pik*,PObj*,PToken*); |
|
497
|
static int pik_round(PNum); |
|
498
|
static void pik_set_var(Pik*,PToken*,PNum,PToken*); |
|
499
|
static PNum pik_value(Pik*,const char*,int,int*); |
|
500
|
static int pik_value_int(Pik*,const char*,int,int*); |
|
501
|
static PNum pik_lookup_color(Pik*,PToken*); |
|
502
|
static PNum pik_get_var(Pik*,PToken*); |
|
503
|
static PNum pik_atof(PToken*); |
|
504
|
static void pik_after_adding_attributes(Pik*,PObj*); |
|
505
|
static void pik_elem_move(PObj*,PNum dx, PNum dy); |
|
506
|
static void pik_elist_move(PList*,PNum dx, PNum dy); |
|
507
|
static void pik_set_numprop(Pik*,PToken*,PRel*); |
|
508
|
static void pik_set_clrprop(Pik*,PToken*,PNum); |
|
509
|
static void pik_set_dashed(Pik*,PToken*,PNum*); |
|
510
|
static void pik_then(Pik*,PToken*,PObj*); |
|
511
|
static void pik_add_direction(Pik*,PToken*,PRel*); |
|
512
|
static void pik_move_hdg(Pik*,PRel*,PToken*,PNum,PToken*,PToken*); |
|
513
|
static void pik_evenwith(Pik*,PToken*,PPoint*); |
|
514
|
static void pik_set_from(Pik*,PObj*,PToken*,PPoint*); |
|
515
|
static void pik_add_to(Pik*,PObj*,PToken*,PPoint*); |
|
516
|
static void pik_close_path(Pik*,PToken*); |
|
517
|
static void pik_set_at(Pik*,PToken*,PPoint*,PToken*); |
|
518
|
static short int pik_nth_value(Pik*,PToken*); |
|
519
|
static PObj *pik_find_nth(Pik*,PObj*,PToken*); |
|
520
|
static PObj *pik_find_byname(Pik*,PObj*,PToken*); |
|
521
|
static PPoint pik_place_of_elem(Pik*,PObj*,PToken*); |
|
522
|
static int pik_bbox_isempty(PBox*); |
|
523
|
static int pik_bbox_contains_point(PBox*,PPoint*); |
|
524
|
static void pik_bbox_init(PBox*); |
|
525
|
static void pik_bbox_addbox(PBox*,PBox*); |
|
526
|
static void pik_bbox_add_xy(PBox*,PNum,PNum); |
|
527
|
static void pik_bbox_addellipse(PBox*,PNum x,PNum y,PNum rx,PNum ry); |
|
528
|
static void pik_add_txt(Pik*,PToken*,int); |
|
529
|
static int pik_text_length(const PToken *pToken, const int isMonospace); |
|
530
|
static void pik_size_to_fit(Pik*,PObj*,PToken*,int); |
|
531
|
static int pik_text_position(int,PToken*); |
|
532
|
static PNum pik_property_of(PObj*,PToken*); |
|
533
|
static PNum pik_func(Pik*,PToken*,PNum,PNum); |
|
534
|
static PPoint pik_position_between(PNum x, PPoint p1, PPoint p2); |
|
535
|
static PPoint pik_position_at_angle(PNum dist, PNum r, PPoint pt); |
|
536
|
static PPoint pik_position_at_hdg(PNum dist, PToken *pD, PPoint pt); |
|
537
|
static void pik_same(Pik *p, PObj*, PToken*); |
|
538
|
static PPoint pik_nth_vertex(Pik *p, PToken *pNth, PToken *pErr, PObj *pObj); |
|
539
|
static PToken pik_next_semantic_token(PToken *pThis); |
|
540
|
static void pik_compute_layout_settings(Pik*); |
|
541
|
static void pik_behind(Pik*,PObj*); |
|
542
|
static PObj *pik_assert(Pik*,PNum,PToken*,PNum); |
|
543
|
static PObj *pik_position_assert(Pik*,PPoint*,PToken*,PPoint*); |
|
544
|
static PNum pik_dist(PPoint*,PPoint*); |
|
545
|
static void pik_add_macro(Pik*,PToken *pId,PToken *pCode); |
|
546
|
|
|
547
|
|
|
548
|
#line 549 "pikchr.c" |
|
549
|
/**************** End of %include directives **********************************/ |
|
550
|
/* These constants specify the various numeric values for terminal symbols. |
|
551
|
***************** Begin token definitions *************************************/ |
|
552
|
#ifndef T_ID |
|
553
|
#define T_ID 1 |
|
554
|
#define T_EDGEPT 2 |
|
555
|
#define T_OF 3 |
|
556
|
#define T_PLUS 4 |
|
557
|
#define T_MINUS 5 |
|
558
|
#define T_STAR 6 |
|
559
|
#define T_SLASH 7 |
|
560
|
#define T_PERCENT 8 |
|
561
|
#define T_UMINUS 9 |
|
562
|
#define T_EOL 10 |
|
563
|
#define T_ASSIGN 11 |
|
564
|
#define T_PLACENAME 12 |
|
565
|
#define T_COLON 13 |
|
566
|
#define T_ASSERT 14 |
|
567
|
#define T_LP 15 |
|
568
|
#define T_EQ 16 |
|
569
|
#define T_RP 17 |
|
570
|
#define T_DEFINE 18 |
|
571
|
#define T_CODEBLOCK 19 |
|
572
|
#define T_FILL 20 |
|
573
|
#define T_COLOR 21 |
|
574
|
#define T_THICKNESS 22 |
|
575
|
#define T_PRINT 23 |
|
576
|
#define T_STRING 24 |
|
577
|
#define T_COMMA 25 |
|
578
|
#define T_ISODATE 26 |
|
579
|
#define T_CLASSNAME 27 |
|
580
|
#define T_LB 28 |
|
581
|
#define T_RB 29 |
|
582
|
#define T_UP 30 |
|
583
|
#define T_DOWN 31 |
|
584
|
#define T_LEFT 32 |
|
585
|
#define T_RIGHT 33 |
|
586
|
#define T_CLOSE 34 |
|
587
|
#define T_CHOP 35 |
|
588
|
#define T_FROM 36 |
|
589
|
#define T_TO 37 |
|
590
|
#define T_THEN 38 |
|
591
|
#define T_HEADING 39 |
|
592
|
#define T_GO 40 |
|
593
|
#define T_AT 41 |
|
594
|
#define T_WITH 42 |
|
595
|
#define T_SAME 43 |
|
596
|
#define T_AS 44 |
|
597
|
#define T_FIT 45 |
|
598
|
#define T_BEHIND 46 |
|
599
|
#define T_UNTIL 47 |
|
600
|
#define T_EVEN 48 |
|
601
|
#define T_DOT_E 49 |
|
602
|
#define T_HEIGHT 50 |
|
603
|
#define T_WIDTH 51 |
|
604
|
#define T_RADIUS 52 |
|
605
|
#define T_DIAMETER 53 |
|
606
|
#define T_DOTTED 54 |
|
607
|
#define T_DASHED 55 |
|
608
|
#define T_CW 56 |
|
609
|
#define T_CCW 57 |
|
610
|
#define T_LARROW 58 |
|
611
|
#define T_RARROW 59 |
|
612
|
#define T_LRARROW 60 |
|
613
|
#define T_INVIS 61 |
|
614
|
#define T_THICK 62 |
|
615
|
#define T_THIN 63 |
|
616
|
#define T_SOLID 64 |
|
617
|
#define T_CENTER 65 |
|
618
|
#define T_LJUST 66 |
|
619
|
#define T_RJUST 67 |
|
620
|
#define T_ABOVE 68 |
|
621
|
#define T_BELOW 69 |
|
622
|
#define T_ITALIC 70 |
|
623
|
#define T_BOLD 71 |
|
624
|
#define T_MONO 72 |
|
625
|
#define T_ALIGNED 73 |
|
626
|
#define T_BIG 74 |
|
627
|
#define T_SMALL 75 |
|
628
|
#define T_AND 76 |
|
629
|
#define T_LT 77 |
|
630
|
#define T_GT 78 |
|
631
|
#define T_ON 79 |
|
632
|
#define T_WAY 80 |
|
633
|
#define T_BETWEEN 81 |
|
634
|
#define T_THE 82 |
|
635
|
#define T_NTH 83 |
|
636
|
#define T_VERTEX 84 |
|
637
|
#define T_TOP 85 |
|
638
|
#define T_BOTTOM 86 |
|
639
|
#define T_START 87 |
|
640
|
#define T_END 88 |
|
641
|
#define T_IN 89 |
|
642
|
#define T_THIS 90 |
|
643
|
#define T_DOT_U 91 |
|
644
|
#define T_LAST 92 |
|
645
|
#define T_NUMBER 93 |
|
646
|
#define T_FUNC1 94 |
|
647
|
#define T_FUNC2 95 |
|
648
|
#define T_DIST 96 |
|
649
|
#define T_DOT_XY 97 |
|
650
|
#define T_X 98 |
|
651
|
#define T_Y 99 |
|
652
|
#define T_DOT_L 100 |
|
653
|
#endif |
|
654
|
/**************** End token definitions ***************************************/ |
|
655
|
|
|
656
|
/* The next sections is a series of control #defines. |
|
657
|
** various aspects of the generated parser. |
|
658
|
** YYCODETYPE is the data type used to store the integer codes |
|
659
|
** that represent terminal and non-terminal symbols. |
|
660
|
** "unsigned char" is used if there are fewer than |
|
661
|
** 256 symbols. Larger types otherwise. |
|
662
|
** YYNOCODE is a number of type YYCODETYPE that is not used for |
|
663
|
** any terminal or nonterminal symbol. |
|
664
|
** YYFALLBACK If defined, this indicates that one or more tokens |
|
665
|
** (also known as: "terminal symbols") have fall-back |
|
666
|
** values which should be used if the original symbol |
|
667
|
** would not parse. This permits keywords to sometimes |
|
668
|
** be used as identifiers, for example. |
|
669
|
** YYACTIONTYPE is the data type used for "action codes" - numbers |
|
670
|
** that indicate what to do in response to the next |
|
671
|
** token. |
|
672
|
** pik_parserTOKENTYPE is the data type used for minor type for terminal |
|
673
|
** symbols. Background: A "minor type" is a semantic |
|
674
|
** value associated with a terminal or non-terminal |
|
675
|
** symbols. For example, for an "ID" terminal symbol, |
|
676
|
** the minor type might be the name of the identifier. |
|
677
|
** Each non-terminal can have a different minor type. |
|
678
|
** Terminal symbols all have the same minor type, though. |
|
679
|
** This macros defines the minor type for terminal |
|
680
|
** symbols. |
|
681
|
** YYMINORTYPE is the data type used for all minor types. |
|
682
|
** This is typically a union of many types, one of |
|
683
|
** which is pik_parserTOKENTYPE. The entry in the union |
|
684
|
** for terminal symbols is called "yy0". |
|
685
|
** YYSTACKDEPTH is the maximum depth of the parser's stack. If |
|
686
|
** zero the stack is dynamically sized using realloc() |
|
687
|
** pik_parserARG_SDECL A static variable declaration for the %extra_argument |
|
688
|
** pik_parserARG_PDECL A parameter declaration for the %extra_argument |
|
689
|
** pik_parserARG_PARAM Code to pass %extra_argument as a subroutine parameter |
|
690
|
** pik_parserARG_STORE Code to store %extra_argument into yypParser |
|
691
|
** pik_parserARG_FETCH Code to extract %extra_argument from yypParser |
|
692
|
** pik_parserCTX_* As pik_parserARG_ except for %extra_context |
|
693
|
** YYREALLOC Name of the realloc() function to use |
|
694
|
** YYFREE Name of the free() function to use |
|
695
|
** YYDYNSTACK True if stack space should be extended on heap |
|
696
|
** YYERRORSYMBOL is the code number of the error symbol. If not |
|
697
|
** defined, then do no error processing. |
|
698
|
** YYNSTATE the combined number of states. |
|
699
|
** YYNRULE the number of rules in the grammar |
|
700
|
** YYNTOKEN Number of terminal symbols |
|
701
|
** YY_MAX_SHIFT Maximum value for shift actions |
|
702
|
** YY_MIN_SHIFTREDUCE Minimum value for shift-reduce actions |
|
703
|
** YY_MAX_SHIFTREDUCE Maximum value for shift-reduce actions |
|
704
|
** YY_ERROR_ACTION The yy_action[] code for syntax error |
|
705
|
** YY_ACCEPT_ACTION The yy_action[] code for accept |
|
706
|
** YY_NO_ACTION The yy_action[] code for no-op |
|
707
|
** YY_MIN_REDUCE Minimum value for reduce actions |
|
708
|
** YY_MAX_REDUCE Maximum value for reduce actions |
|
709
|
** YY_MIN_DSTRCTR Minimum symbol value that has a destructor |
|
710
|
** YY_MAX_DSTRCTR Maximum symbol value that has a destructor |
|
711
|
*/ |
|
712
|
#ifndef INTERFACE |
|
713
|
# define INTERFACE 1 |
|
714
|
#endif |
|
715
|
/************* Begin control #defines *****************************************/ |
|
716
|
#define YYCODETYPE unsigned char |
|
717
|
#define YYNOCODE 138 |
|
718
|
#define YYACTIONTYPE unsigned short int |
|
719
|
#define pik_parserTOKENTYPE PToken |
|
720
|
typedef union { |
|
721
|
int yyinit; |
|
722
|
pik_parserTOKENTYPE yy0; |
|
723
|
PList* yy23; |
|
724
|
PRel yy28; |
|
725
|
PObj* yy54; |
|
726
|
PNum yy129; |
|
727
|
PPoint yy187; |
|
728
|
short int yy272; |
|
729
|
} YYMINORTYPE; |
|
730
|
#ifndef YYSTACKDEPTH |
|
731
|
#define YYSTACKDEPTH 100 |
|
732
|
#endif |
|
733
|
#define pik_parserARG_SDECL |
|
734
|
#define pik_parserARG_PDECL |
|
735
|
#define pik_parserARG_PARAM |
|
736
|
#define pik_parserARG_FETCH |
|
737
|
#define pik_parserARG_STORE |
|
738
|
#define YYREALLOC realloc |
|
739
|
#define YYFREE free |
|
740
|
#define YYDYNSTACK 0 |
|
741
|
#define pik_parserCTX_SDECL Pik *p; |
|
742
|
#define pik_parserCTX_PDECL ,Pik *p |
|
743
|
#define pik_parserCTX_PARAM ,p |
|
744
|
#define pik_parserCTX_FETCH Pik *p=yypParser->p; |
|
745
|
#define pik_parserCTX_STORE yypParser->p=p; |
|
746
|
#define YYFALLBACK 1 |
|
747
|
#define YYNSTATE 164 |
|
748
|
#define YYNRULE 156 |
|
749
|
#define YYNRULE_WITH_ACTION 116 |
|
750
|
#define YYNTOKEN 101 |
|
751
|
#define YY_MAX_SHIFT 163 |
|
752
|
#define YY_MIN_SHIFTREDUCE 287 |
|
753
|
#define YY_MAX_SHIFTREDUCE 442 |
|
754
|
#define YY_ERROR_ACTION 443 |
|
755
|
#define YY_ACCEPT_ACTION 444 |
|
756
|
#define YY_NO_ACTION 445 |
|
757
|
#define YY_MIN_REDUCE 446 |
|
758
|
#define YY_MAX_REDUCE 601 |
|
759
|
#define YY_MIN_DSTRCTR 101 |
|
760
|
#define YY_MAX_DSTRCTR 104 |
|
761
|
/************* End control #defines *******************************************/ |
|
762
|
#define YY_NLOOKAHEAD ((int)(sizeof(yy_lookahead)/sizeof(yy_lookahead[0]))) |
|
763
|
|
|
764
|
/* Define the yytestcase() macro to be a no-op if is not already defined |
|
765
|
** otherwise. |
|
766
|
** |
|
767
|
** Applications can choose to define yytestcase() in the %include section |
|
768
|
** to a macro that can assist in verifying code coverage. For production |
|
769
|
** code the yytestcase() macro should be turned off. But it is useful |
|
770
|
** for testing. |
|
771
|
*/ |
|
772
|
#ifndef yytestcase |
|
773
|
# define yytestcase(X) |
|
774
|
#endif |
|
775
|
|
|
776
|
/* Macro to determine if stack space has the ability to grow using |
|
777
|
** heap memory. |
|
778
|
*/ |
|
779
|
#if YYSTACKDEPTH<=0 || YYDYNSTACK |
|
780
|
# define YYGROWABLESTACK 1 |
|
781
|
#else |
|
782
|
# define YYGROWABLESTACK 0 |
|
783
|
#endif |
|
784
|
|
|
785
|
/* Guarantee a minimum number of initial stack slots. |
|
786
|
*/ |
|
787
|
#if YYSTACKDEPTH<=0 |
|
788
|
# undef YYSTACKDEPTH |
|
789
|
# define YYSTACKDEPTH 2 /* Need a minimum stack size */ |
|
790
|
#endif |
|
791
|
|
|
792
|
|
|
793
|
/* Next are the tables used to determine what action to take based on the |
|
794
|
** current state and lookahead token. These tables are used to implement |
|
795
|
** functions that take a state number and lookahead value and return an |
|
796
|
** action integer. |
|
797
|
** |
|
798
|
** Suppose the action integer is N. Then the action is determined as |
|
799
|
** follows |
|
800
|
** |
|
801
|
** 0 <= N <= YY_MAX_SHIFT Shift N. That is, push the lookahead |
|
802
|
** token onto the stack and goto state N. |
|
803
|
** |
|
804
|
** N between YY_MIN_SHIFTREDUCE Shift to an arbitrary state then |
|
805
|
** and YY_MAX_SHIFTREDUCE reduce by rule N-YY_MIN_SHIFTREDUCE. |
|
806
|
** |
|
807
|
** N == YY_ERROR_ACTION A syntax error has occurred. |
|
808
|
** |
|
809
|
** N == YY_ACCEPT_ACTION The parser accepts its input. |
|
810
|
** |
|
811
|
** N == YY_NO_ACTION No such action. Denotes unused |
|
812
|
** slots in the yy_action[] table. |
|
813
|
** |
|
814
|
** N between YY_MIN_REDUCE Reduce by rule N-YY_MIN_REDUCE |
|
815
|
** and YY_MAX_REDUCE |
|
816
|
** |
|
817
|
** The action table is constructed as a single large table named yy_action[]. |
|
818
|
** Given state S and lookahead X, the action is computed as either: |
|
819
|
** |
|
820
|
** (A) N = yy_action[ yy_shift_ofst[S] + X ] |
|
821
|
** (B) N = yy_default[S] |
|
822
|
** |
|
823
|
** The (A) formula is preferred. The B formula is used instead if |
|
824
|
** yy_lookahead[yy_shift_ofst[S]+X] is not equal to X. |
|
825
|
** |
|
826
|
** The formulas above are for computing the action when the lookahead is |
|
827
|
** a terminal symbol. If the lookahead is a non-terminal (as occurs after |
|
828
|
** a reduce action) then the yy_reduce_ofst[] array is used in place of |
|
829
|
** the yy_shift_ofst[] array. |
|
830
|
** |
|
831
|
** The following are the tables generated in this section: |
|
832
|
** |
|
833
|
** yy_action[] A single table containing all actions. |
|
834
|
** yy_lookahead[] A table containing the lookahead for each entry in |
|
835
|
** yy_action. Used to detect hash collisions. |
|
836
|
** yy_shift_ofst[] For each state, the offset into yy_action for |
|
837
|
** shifting terminals. |
|
838
|
** yy_reduce_ofst[] For each state, the offset into yy_action for |
|
839
|
** shifting non-terminals after a reduce. |
|
840
|
** yy_default[] Default action for each state. |
|
841
|
** |
|
842
|
*********** Begin parsing tables **********************************************/ |
|
843
|
#define YY_ACTTAB_COUNT (1305) |
|
844
|
static const YYACTIONTYPE yy_action[] = { |
|
845
|
/* 0 */ 575, 495, 161, 119, 25, 452, 29, 74, 129, 148, |
|
846
|
/* 10 */ 575, 64, 63, 62, 61, 453, 113, 120, 161, 119, |
|
847
|
/* 20 */ 427, 428, 339, 357, 81, 121, 447, 454, 29, 575, |
|
848
|
/* 30 */ 530, 13, 50, 450, 322, 323, 9, 8, 33, 149, |
|
849
|
/* 40 */ 32, 7, 71, 127, 163, 335, 66, 28, 444, 27, |
|
850
|
/* 50 */ 339, 339, 339, 339, 425, 426, 340, 341, 342, 343, |
|
851
|
/* 60 */ 344, 345, 346, 347, 348, 474, 64, 63, 62, 61, |
|
852
|
/* 70 */ 54, 51, 73, 306, 148, 474, 492, 161, 119, 297, |
|
853
|
/* 80 */ 112, 113, 120, 161, 119, 427, 428, 339, 30, 81, |
|
854
|
/* 90 */ 109, 447, 454, 29, 474, 528, 161, 119, 450, 322, |
|
855
|
/* 100 */ 323, 9, 8, 33, 149, 32, 7, 71, 127, 163, |
|
856
|
/* 110 */ 335, 66, 535, 36, 27, 339, 339, 339, 339, 425, |
|
857
|
/* 120 */ 426, 340, 341, 342, 343, 344, 345, 346, 347, 348, |
|
858
|
/* 130 */ 394, 435, 310, 59, 60, 64, 63, 62, 61, 313, |
|
859
|
/* 140 */ 74, 376, 148, 69, 2, 533, 161, 119, 124, 113, |
|
860
|
/* 150 */ 120, 161, 119, 80, 535, 31, 308, 79, 83, 107, |
|
861
|
/* 160 */ 535, 441, 440, 535, 394, 435, 299, 59, 60, 120, |
|
862
|
/* 170 */ 161, 119, 149, 463, 376, 376, 330, 84, 2, 122, |
|
863
|
/* 180 */ 78, 78, 38, 156, 156, 156, 48, 37, 559, 328, |
|
864
|
/* 190 */ 128, 152, 560, 561, 434, 441, 440, 350, 350, 350, |
|
865
|
/* 200 */ 350, 350, 350, 350, 350, 350, 350, 350, 577, 77, |
|
866
|
/* 210 */ 577, 35, 106, 46, 436, 437, 438, 439, 579, 375, |
|
867
|
/* 220 */ 298, 117, 393, 155, 154, 153, 47, 4, 434, 69, |
|
868
|
/* 230 */ 394, 435, 3, 59, 60, 411, 412, 413, 414, 398, |
|
869
|
/* 240 */ 399, 376, 62, 61, 2, 108, 106, 5, 436, 437, |
|
870
|
/* 250 */ 438, 439, 375, 375, 117, 117, 393, 155, 154, 153, |
|
871
|
/* 260 */ 76, 441, 440, 67, 6, 142, 140, 64, 63, 62, |
|
872
|
/* 270 */ 61, 380, 157, 424, 427, 428, 339, 379, 159, 45, |
|
873
|
/* 280 */ 423, 72, 131, 148, 531, 161, 119, 1, 55, 125, |
|
874
|
/* 290 */ 113, 120, 161, 119, 434, 147, 146, 64, 63, 62, |
|
875
|
/* 300 */ 61, 397, 43, 11, 339, 339, 339, 339, 425, 426, |
|
876
|
/* 310 */ 355, 65, 106, 149, 436, 437, 438, 439, 74, 375, |
|
877
|
/* 320 */ 148, 117, 393, 155, 154, 153, 497, 113, 120, 161, |
|
878
|
/* 330 */ 119, 22, 21, 12, 142, 140, 64, 63, 62, 61, |
|
879
|
/* 340 */ 24, 356, 145, 141, 431, 64, 63, 62, 61, 391, |
|
880
|
/* 350 */ 149, 448, 454, 29, 378, 158, 85, 55, 450, 394, |
|
881
|
/* 360 */ 432, 138, 59, 60, 147, 146, 120, 161, 119, 163, |
|
882
|
/* 370 */ 102, 43, 139, 42, 27, 430, 14, 15, 301, 302, |
|
883
|
/* 380 */ 303, 446, 305, 16, 44, 74, 18, 148, 152, 19, |
|
884
|
/* 390 */ 20, 36, 68, 496, 113, 120, 161, 119, 114, 359, |
|
885
|
/* 400 */ 22, 21, 23, 142, 140, 64, 63, 62, 61, 24, |
|
886
|
/* 410 */ 107, 145, 141, 431, 26, 57, 377, 149, 58, 118, |
|
887
|
/* 420 */ 120, 161, 119, 392, 463, 384, 55, 64, 63, 62, |
|
888
|
/* 430 */ 61, 382, 569, 147, 146, 160, 383, 435, 39, 70, |
|
889
|
/* 440 */ 43, 106, 152, 445, 445, 88, 445, 445, 375, 445, |
|
890
|
/* 450 */ 117, 393, 155, 154, 153, 120, 161, 119, 445, 17, |
|
891
|
/* 460 */ 445, 10, 479, 479, 445, 445, 435, 441, 440, 22, |
|
892
|
/* 470 */ 21, 445, 403, 64, 63, 62, 61, 152, 24, 445, |
|
893
|
/* 480 */ 145, 141, 431, 133, 75, 126, 354, 445, 445, 123, |
|
894
|
/* 490 */ 445, 404, 405, 406, 408, 80, 441, 440, 308, 79, |
|
895
|
/* 500 */ 434, 411, 412, 413, 414, 394, 445, 445, 59, 60, |
|
896
|
/* 510 */ 64, 63, 62, 61, 445, 445, 376, 445, 445, 42, |
|
897
|
/* 520 */ 436, 437, 438, 439, 156, 156, 156, 394, 445, 434, |
|
898
|
/* 530 */ 59, 60, 64, 63, 62, 61, 445, 445, 376, 445, |
|
899
|
/* 540 */ 445, 42, 445, 394, 473, 391, 59, 60, 445, 436, |
|
900
|
/* 550 */ 437, 438, 439, 49, 376, 445, 74, 42, 148, 445, |
|
901
|
/* 560 */ 88, 445, 445, 445, 490, 113, 120, 161, 119, 445, |
|
902
|
/* 570 */ 120, 161, 119, 132, 130, 394, 143, 475, 59, 60, |
|
903
|
/* 580 */ 445, 473, 64, 63, 62, 61, 376, 106, 149, 42, |
|
904
|
/* 590 */ 445, 445, 152, 445, 375, 391, 117, 393, 155, 154, |
|
905
|
/* 600 */ 153, 394, 144, 52, 59, 60, 445, 445, 445, 106, |
|
906
|
/* 610 */ 445, 445, 376, 445, 445, 42, 375, 445, 117, 393, |
|
907
|
/* 620 */ 155, 154, 153, 445, 445, 106, 64, 63, 62, 61, |
|
908
|
/* 630 */ 445, 445, 375, 445, 117, 393, 155, 154, 153, 394, |
|
909
|
/* 640 */ 445, 445, 59, 60, 88, 445, 445, 53, 445, 445, |
|
910
|
/* 650 */ 376, 445, 445, 42, 120, 161, 119, 106, 445, 445, |
|
911
|
/* 660 */ 445, 110, 110, 445, 375, 445, 117, 393, 155, 154, |
|
912
|
/* 670 */ 153, 394, 445, 445, 59, 60, 152, 107, 445, 445, |
|
913
|
/* 680 */ 445, 445, 102, 106, 445, 42, 445, 120, 161, 119, |
|
914
|
/* 690 */ 375, 451, 117, 393, 155, 154, 153, 394, 445, 445, |
|
915
|
/* 700 */ 59, 60, 64, 63, 62, 61, 445, 445, 376, 152, |
|
916
|
/* 710 */ 445, 40, 445, 394, 445, 396, 59, 60, 445, 445, |
|
917
|
/* 720 */ 445, 106, 445, 445, 376, 88, 445, 41, 375, 445, |
|
918
|
/* 730 */ 117, 393, 155, 154, 153, 120, 161, 119, 74, 445, |
|
919
|
/* 740 */ 148, 445, 111, 111, 107, 445, 484, 113, 120, 161, |
|
920
|
/* 750 */ 119, 445, 445, 106, 120, 161, 119, 152, 478, 445, |
|
921
|
/* 760 */ 375, 86, 117, 393, 155, 154, 153, 445, 445, 445, |
|
922
|
/* 770 */ 149, 120, 161, 119, 445, 445, 152, 445, 445, 106, |
|
923
|
/* 780 */ 445, 64, 63, 62, 61, 445, 375, 445, 117, 393, |
|
924
|
/* 790 */ 155, 154, 153, 152, 395, 106, 64, 63, 62, 61, |
|
925
|
/* 800 */ 98, 445, 375, 445, 117, 393, 155, 154, 153, 445, |
|
926
|
/* 810 */ 120, 161, 119, 445, 74, 445, 148, 56, 445, 74, |
|
927
|
/* 820 */ 445, 148, 483, 113, 120, 161, 119, 480, 113, 120, |
|
928
|
/* 830 */ 161, 119, 152, 74, 445, 148, 445, 89, 445, 445, |
|
929
|
/* 840 */ 445, 134, 113, 120, 161, 119, 149, 120, 161, 119, |
|
930
|
/* 850 */ 445, 149, 74, 445, 148, 445, 445, 445, 378, 158, |
|
931
|
/* 860 */ 517, 113, 120, 161, 119, 149, 74, 445, 148, 152, |
|
932
|
/* 870 */ 445, 74, 445, 148, 137, 113, 120, 161, 119, 525, |
|
933
|
/* 880 */ 113, 120, 161, 119, 149, 74, 445, 148, 64, 63, |
|
934
|
/* 890 */ 62, 61, 445, 527, 113, 120, 161, 119, 149, 445, |
|
935
|
/* 900 */ 445, 391, 445, 149, 445, 445, 445, 445, 445, 445, |
|
936
|
/* 910 */ 74, 445, 148, 445, 445, 162, 445, 149, 524, 113, |
|
937
|
/* 920 */ 120, 161, 119, 118, 445, 74, 445, 148, 445, 445, |
|
938
|
/* 930 */ 445, 445, 445, 526, 113, 120, 161, 119, 445, 74, |
|
939
|
/* 940 */ 445, 148, 149, 445, 445, 445, 445, 523, 113, 120, |
|
940
|
/* 950 */ 161, 119, 74, 445, 148, 445, 445, 149, 445, 445, |
|
941
|
/* 960 */ 522, 113, 120, 161, 119, 445, 74, 445, 148, 445, |
|
942
|
/* 970 */ 445, 149, 445, 445, 521, 113, 120, 161, 119, 74, |
|
943
|
/* 980 */ 445, 148, 445, 445, 149, 445, 445, 520, 113, 120, |
|
944
|
/* 990 */ 161, 119, 445, 74, 445, 148, 445, 445, 149, 445, |
|
945
|
/* 1000 */ 445, 519, 113, 120, 161, 119, 445, 445, 445, 445, |
|
946
|
/* 1010 */ 445, 149, 445, 445, 445, 445, 445, 445, 74, 445, |
|
947
|
/* 1020 */ 148, 445, 445, 445, 445, 149, 150, 113, 120, 161, |
|
948
|
/* 1030 */ 119, 74, 445, 148, 445, 445, 445, 445, 445, 151, |
|
949
|
/* 1040 */ 113, 120, 161, 119, 445, 74, 445, 148, 445, 445, |
|
950
|
/* 1050 */ 149, 445, 445, 136, 113, 120, 161, 119, 74, 445, |
|
951
|
/* 1060 */ 148, 445, 445, 149, 445, 445, 135, 113, 120, 161, |
|
952
|
/* 1070 */ 119, 445, 88, 445, 445, 445, 445, 149, 445, 445, |
|
953
|
/* 1080 */ 445, 90, 120, 161, 119, 445, 445, 445, 445, 82, |
|
954
|
/* 1090 */ 149, 120, 161, 119, 445, 87, 466, 445, 34, 99, |
|
955
|
/* 1100 */ 445, 445, 445, 445, 152, 120, 161, 119, 100, 120, |
|
956
|
/* 1110 */ 161, 119, 445, 152, 445, 445, 445, 445, 120, 161, |
|
957
|
/* 1120 */ 119, 445, 445, 445, 101, 445, 445, 152, 445, 445, |
|
958
|
/* 1130 */ 445, 152, 91, 445, 120, 161, 119, 103, 445, 445, |
|
959
|
/* 1140 */ 152, 445, 120, 161, 119, 445, 445, 120, 161, 119, |
|
960
|
/* 1150 */ 445, 92, 445, 445, 445, 445, 152, 445, 445, 445, |
|
961
|
/* 1160 */ 93, 120, 161, 119, 152, 445, 104, 445, 445, 152, |
|
962
|
/* 1170 */ 120, 161, 119, 445, 94, 445, 120, 161, 119, 445, |
|
963
|
/* 1180 */ 445, 445, 445, 152, 120, 161, 119, 445, 445, 105, |
|
964
|
/* 1190 */ 445, 445, 152, 445, 445, 445, 445, 95, 152, 120, |
|
965
|
/* 1200 */ 161, 119, 96, 445, 445, 97, 152, 120, 161, 119, |
|
966
|
/* 1210 */ 445, 445, 120, 161, 119, 120, 161, 119, 445, 445, |
|
967
|
/* 1220 */ 445, 152, 445, 445, 445, 445, 445, 445, 445, 152, |
|
968
|
/* 1230 */ 549, 445, 445, 548, 152, 445, 445, 152, 547, 445, |
|
969
|
/* 1240 */ 120, 161, 119, 120, 161, 119, 546, 445, 120, 161, |
|
970
|
/* 1250 */ 119, 445, 445, 445, 445, 445, 120, 161, 119, 445, |
|
971
|
/* 1260 */ 445, 445, 152, 445, 445, 152, 445, 445, 445, 115, |
|
972
|
/* 1270 */ 152, 445, 116, 445, 445, 445, 445, 445, 152, 120, |
|
973
|
/* 1280 */ 161, 119, 120, 161, 119, 445, 445, 445, 445, 445, |
|
974
|
/* 1290 */ 445, 445, 445, 445, 445, 445, 445, 445, 445, 445, |
|
975
|
/* 1300 */ 445, 152, 445, 445, 152, |
|
976
|
}; |
|
977
|
static const YYCODETYPE yy_lookahead[] = { |
|
978
|
/* 0 */ 0, 115, 116, 117, 136, 103, 104, 105, 107, 107, |
|
979
|
/* 10 */ 10, 4, 5, 6, 7, 113, 114, 115, 116, 117, |
|
980
|
/* 20 */ 20, 21, 22, 17, 24, 101, 102, 103, 104, 29, |
|
981
|
/* 30 */ 107, 25, 25, 109, 34, 35, 36, 37, 38, 137, |
|
982
|
/* 40 */ 40, 41, 42, 43, 120, 45, 46, 109, 124, 125, |
|
983
|
/* 50 */ 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, |
|
984
|
/* 60 */ 60, 61, 62, 63, 64, 0, 4, 5, 6, 7, |
|
985
|
/* 70 */ 4, 5, 105, 25, 107, 10, 115, 116, 117, 17, |
|
986
|
/* 80 */ 113, 114, 115, 116, 117, 20, 21, 22, 128, 24, |
|
987
|
/* 90 */ 101, 102, 103, 104, 29, 115, 116, 117, 109, 34, |
|
988
|
/* 100 */ 35, 36, 37, 38, 137, 40, 41, 42, 43, 120, |
|
989
|
/* 110 */ 45, 46, 49, 10, 125, 50, 51, 52, 53, 54, |
|
990
|
/* 120 */ 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, |
|
991
|
/* 130 */ 1, 2, 29, 4, 5, 4, 5, 6, 7, 8, |
|
992
|
/* 140 */ 105, 12, 107, 3, 15, 115, 116, 117, 113, 114, |
|
993
|
/* 150 */ 115, 116, 117, 24, 91, 130, 27, 28, 118, 105, |
|
994
|
/* 160 */ 97, 32, 33, 100, 1, 2, 19, 4, 5, 115, |
|
995
|
/* 170 */ 116, 117, 137, 119, 12, 12, 2, 118, 15, 1, |
|
996
|
/* 180 */ 126, 127, 106, 20, 21, 22, 110, 111, 106, 2, |
|
997
|
/* 190 */ 107, 137, 110, 111, 65, 32, 33, 65, 66, 67, |
|
998
|
/* 200 */ 68, 69, 70, 71, 72, 73, 74, 75, 132, 133, |
|
999
|
/* 210 */ 134, 131, 83, 39, 85, 86, 87, 88, 135, 90, |
|
1000
|
/* 220 */ 17, 92, 93, 94, 95, 96, 39, 15, 65, 89, |
|
1001
|
/* 230 */ 1, 2, 16, 4, 5, 30, 31, 32, 33, 98, |
|
1002
|
/* 240 */ 99, 12, 6, 7, 15, 83, 83, 41, 85, 86, |
|
1003
|
/* 250 */ 87, 88, 90, 90, 92, 92, 93, 94, 95, 96, |
|
1004
|
/* 260 */ 49, 32, 33, 44, 41, 2, 3, 4, 5, 6, |
|
1005
|
/* 270 */ 7, 27, 28, 42, 20, 21, 22, 27, 28, 16, |
|
1006
|
/* 280 */ 42, 105, 48, 107, 115, 116, 117, 13, 25, 113, |
|
1007
|
/* 290 */ 114, 115, 116, 117, 65, 32, 33, 4, 5, 6, |
|
1008
|
/* 300 */ 7, 17, 39, 25, 50, 51, 52, 53, 54, 55, |
|
1009
|
/* 310 */ 17, 100, 83, 137, 85, 86, 87, 88, 105, 90, |
|
1010
|
/* 320 */ 107, 92, 93, 94, 95, 96, 113, 114, 115, 116, |
|
1011
|
/* 330 */ 117, 68, 69, 76, 2, 3, 4, 5, 6, 7, |
|
1012
|
/* 340 */ 77, 17, 79, 80, 81, 4, 5, 6, 7, 17, |
|
1013
|
/* 350 */ 137, 102, 103, 104, 27, 28, 105, 25, 109, 1, |
|
1014
|
/* 360 */ 81, 80, 4, 5, 32, 33, 115, 116, 117, 120, |
|
1015
|
/* 370 */ 12, 39, 82, 15, 125, 81, 3, 36, 20, 21, |
|
1016
|
/* 380 */ 22, 0, 24, 3, 39, 105, 3, 107, 137, 3, |
|
1017
|
/* 390 */ 3, 10, 3, 113, 114, 115, 116, 117, 97, 78, |
|
1018
|
/* 400 */ 68, 69, 25, 2, 3, 4, 5, 6, 7, 77, |
|
1019
|
/* 410 */ 105, 79, 80, 81, 15, 15, 12, 137, 15, 92, |
|
1020
|
/* 420 */ 115, 116, 117, 17, 119, 29, 25, 4, 5, 6, |
|
1021
|
/* 430 */ 7, 29, 127, 32, 33, 91, 29, 2, 11, 3, |
|
1022
|
/* 440 */ 39, 83, 137, 138, 138, 105, 138, 138, 90, 138, |
|
1023
|
/* 450 */ 92, 93, 94, 95, 96, 115, 116, 117, 138, 36, |
|
1024
|
/* 460 */ 138, 121, 122, 123, 138, 138, 2, 32, 33, 68, |
|
1025
|
/* 470 */ 69, 138, 1, 4, 5, 6, 7, 137, 77, 138, |
|
1026
|
/* 480 */ 79, 80, 81, 12, 49, 14, 17, 138, 138, 18, |
|
1027
|
/* 490 */ 138, 20, 21, 22, 23, 24, 32, 33, 27, 28, |
|
1028
|
/* 500 */ 65, 30, 31, 32, 33, 1, 138, 138, 4, 5, |
|
1029
|
/* 510 */ 4, 5, 6, 7, 138, 138, 12, 138, 138, 15, |
|
1030
|
/* 520 */ 85, 86, 87, 88, 20, 21, 22, 1, 138, 65, |
|
1031
|
/* 530 */ 4, 5, 4, 5, 6, 7, 138, 138, 12, 138, |
|
1032
|
/* 540 */ 138, 15, 138, 1, 2, 17, 4, 5, 138, 85, |
|
1033
|
/* 550 */ 86, 87, 88, 25, 12, 138, 105, 15, 107, 138, |
|
1034
|
/* 560 */ 105, 138, 138, 138, 113, 114, 115, 116, 117, 138, |
|
1035
|
/* 570 */ 115, 116, 117, 47, 48, 1, 2, 122, 4, 5, |
|
1036
|
/* 580 */ 138, 39, 4, 5, 6, 7, 12, 83, 137, 15, |
|
1037
|
/* 590 */ 138, 138, 137, 138, 90, 17, 92, 93, 94, 95, |
|
1038
|
/* 600 */ 96, 1, 2, 25, 4, 5, 138, 138, 138, 83, |
|
1039
|
/* 610 */ 138, 138, 12, 138, 138, 15, 90, 138, 92, 93, |
|
1040
|
/* 620 */ 94, 95, 96, 138, 138, 83, 4, 5, 6, 7, |
|
1041
|
/* 630 */ 138, 138, 90, 138, 92, 93, 94, 95, 96, 1, |
|
1042
|
/* 640 */ 138, 138, 4, 5, 105, 138, 138, 25, 138, 138, |
|
1043
|
/* 650 */ 12, 138, 138, 15, 115, 116, 117, 83, 138, 138, |
|
1044
|
/* 660 */ 138, 122, 123, 138, 90, 138, 92, 93, 94, 95, |
|
1045
|
/* 670 */ 96, 1, 138, 138, 4, 5, 137, 105, 138, 138, |
|
1046
|
/* 680 */ 138, 138, 12, 83, 138, 15, 138, 115, 116, 117, |
|
1047
|
/* 690 */ 90, 119, 92, 93, 94, 95, 96, 1, 138, 138, |
|
1048
|
/* 700 */ 4, 5, 4, 5, 6, 7, 138, 138, 12, 137, |
|
1049
|
/* 710 */ 138, 15, 138, 1, 138, 17, 4, 5, 138, 138, |
|
1050
|
/* 720 */ 138, 83, 138, 138, 12, 105, 138, 15, 90, 138, |
|
1051
|
/* 730 */ 92, 93, 94, 95, 96, 115, 116, 117, 105, 138, |
|
1052
|
/* 740 */ 107, 138, 122, 123, 105, 138, 113, 114, 115, 116, |
|
1053
|
/* 750 */ 117, 138, 138, 83, 115, 116, 117, 137, 119, 138, |
|
1054
|
/* 760 */ 90, 105, 92, 93, 94, 95, 96, 138, 138, 138, |
|
1055
|
/* 770 */ 137, 115, 116, 117, 138, 138, 137, 138, 138, 83, |
|
1056
|
/* 780 */ 138, 4, 5, 6, 7, 138, 90, 138, 92, 93, |
|
1057
|
/* 790 */ 94, 95, 96, 137, 17, 83, 4, 5, 6, 7, |
|
1058
|
/* 800 */ 105, 138, 90, 138, 92, 93, 94, 95, 96, 138, |
|
1059
|
/* 810 */ 115, 116, 117, 138, 105, 138, 107, 25, 138, 105, |
|
1060
|
/* 820 */ 138, 107, 113, 114, 115, 116, 117, 113, 114, 115, |
|
1061
|
/* 830 */ 116, 117, 137, 105, 138, 107, 138, 105, 138, 138, |
|
1062
|
/* 840 */ 138, 113, 114, 115, 116, 117, 137, 115, 116, 117, |
|
1063
|
/* 850 */ 138, 137, 105, 138, 107, 138, 138, 138, 27, 28, |
|
1064
|
/* 860 */ 113, 114, 115, 116, 117, 137, 105, 138, 107, 137, |
|
1065
|
/* 870 */ 138, 105, 138, 107, 113, 114, 115, 116, 117, 113, |
|
1066
|
/* 880 */ 114, 115, 116, 117, 137, 105, 138, 107, 4, 5, |
|
1067
|
/* 890 */ 6, 7, 138, 113, 114, 115, 116, 117, 137, 138, |
|
1068
|
/* 900 */ 138, 17, 138, 137, 138, 138, 138, 138, 138, 138, |
|
1069
|
/* 910 */ 105, 138, 107, 138, 138, 84, 138, 137, 113, 114, |
|
1070
|
/* 920 */ 115, 116, 117, 92, 138, 105, 138, 107, 138, 138, |
|
1071
|
/* 930 */ 138, 138, 138, 113, 114, 115, 116, 117, 138, 105, |
|
1072
|
/* 940 */ 138, 107, 137, 138, 138, 138, 138, 113, 114, 115, |
|
1073
|
/* 950 */ 116, 117, 105, 138, 107, 138, 138, 137, 138, 138, |
|
1074
|
/* 960 */ 113, 114, 115, 116, 117, 138, 105, 138, 107, 138, |
|
1075
|
/* 970 */ 138, 137, 138, 138, 113, 114, 115, 116, 117, 105, |
|
1076
|
/* 980 */ 138, 107, 138, 138, 137, 138, 138, 113, 114, 115, |
|
1077
|
/* 990 */ 116, 117, 138, 105, 138, 107, 138, 138, 137, 138, |
|
1078
|
/* 1000 */ 138, 113, 114, 115, 116, 117, 138, 138, 138, 138, |
|
1079
|
/* 1010 */ 138, 137, 138, 138, 138, 138, 138, 138, 105, 138, |
|
1080
|
/* 1020 */ 107, 138, 138, 138, 138, 137, 113, 114, 115, 116, |
|
1081
|
/* 1030 */ 117, 105, 138, 107, 138, 138, 138, 138, 138, 113, |
|
1082
|
/* 1040 */ 114, 115, 116, 117, 138, 105, 138, 107, 138, 138, |
|
1083
|
/* 1050 */ 137, 138, 138, 113, 114, 115, 116, 117, 105, 138, |
|
1084
|
/* 1060 */ 107, 138, 138, 137, 138, 138, 113, 114, 115, 116, |
|
1085
|
/* 1070 */ 117, 138, 105, 138, 138, 138, 138, 137, 138, 138, |
|
1086
|
/* 1080 */ 138, 105, 115, 116, 117, 138, 138, 138, 138, 122, |
|
1087
|
/* 1090 */ 137, 115, 116, 117, 138, 105, 129, 138, 131, 105, |
|
1088
|
/* 1100 */ 138, 138, 138, 138, 137, 115, 116, 117, 105, 115, |
|
1089
|
/* 1110 */ 116, 117, 138, 137, 138, 138, 138, 138, 115, 116, |
|
1090
|
/* 1120 */ 117, 138, 138, 138, 105, 138, 138, 137, 138, 138, |
|
1091
|
/* 1130 */ 138, 137, 105, 138, 115, 116, 117, 105, 138, 138, |
|
1092
|
/* 1140 */ 137, 138, 115, 116, 117, 138, 138, 115, 116, 117, |
|
1093
|
/* 1150 */ 138, 105, 138, 138, 138, 138, 137, 138, 138, 138, |
|
1094
|
/* 1160 */ 105, 115, 116, 117, 137, 138, 105, 138, 138, 137, |
|
1095
|
/* 1170 */ 115, 116, 117, 138, 105, 138, 115, 116, 117, 138, |
|
1096
|
/* 1180 */ 138, 138, 138, 137, 115, 116, 117, 138, 138, 105, |
|
1097
|
/* 1190 */ 138, 138, 137, 138, 138, 138, 138, 105, 137, 115, |
|
1098
|
/* 1200 */ 116, 117, 105, 138, 138, 105, 137, 115, 116, 117, |
|
1099
|
/* 1210 */ 138, 138, 115, 116, 117, 115, 116, 117, 138, 138, |
|
1100
|
/* 1220 */ 138, 137, 138, 138, 138, 138, 138, 138, 138, 137, |
|
1101
|
/* 1230 */ 105, 138, 138, 105, 137, 138, 138, 137, 105, 138, |
|
1102
|
/* 1240 */ 115, 116, 117, 115, 116, 117, 105, 138, 115, 116, |
|
1103
|
/* 1250 */ 117, 138, 138, 138, 138, 138, 115, 116, 117, 138, |
|
1104
|
/* 1260 */ 138, 138, 137, 138, 138, 137, 138, 138, 138, 105, |
|
1105
|
/* 1270 */ 137, 138, 105, 138, 138, 138, 138, 138, 137, 115, |
|
1106
|
/* 1280 */ 116, 117, 115, 116, 117, 138, 138, 138, 138, 138, |
|
1107
|
/* 1290 */ 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, |
|
1108
|
/* 1300 */ 138, 137, 138, 138, 137, 101, 101, 101, 101, 101, |
|
1109
|
/* 1310 */ 101, 101, 101, 101, 101, 101, 101, 101, 101, 101, |
|
1110
|
/* 1320 */ 101, 101, 101, 101, 101, 101, 101, 101, 101, 101, |
|
1111
|
/* 1330 */ 101, 101, 101, 101, 101, 101, 101, 101, 101, 101, |
|
1112
|
/* 1340 */ 101, 101, 101, 101, 101, 101, 101, 101, 101, 101, |
|
1113
|
/* 1350 */ 101, 101, 101, 101, 101, 101, 101, 101, 101, 101, |
|
1114
|
/* 1360 */ 101, 101, 101, 101, 101, 101, 101, 101, 101, 101, |
|
1115
|
/* 1370 */ 101, 101, 101, 101, 101, 101, 101, 101, 101, 101, |
|
1116
|
/* 1380 */ 101, 101, 101, 101, 101, 101, 101, 101, 101, 101, |
|
1117
|
/* 1390 */ 101, 101, 101, 101, 101, 101, 101, 101, 101, 101, |
|
1118
|
/* 1400 */ 101, 101, 101, 101, 101, 101, |
|
1119
|
}; |
|
1120
|
#define YY_SHIFT_COUNT (163) |
|
1121
|
#define YY_SHIFT_MIN (0) |
|
1122
|
#define YY_SHIFT_MAX (884) |
|
1123
|
static const unsigned short int yy_shift_ofst[] = { |
|
1124
|
/* 0 */ 471, 129, 163, 229, 229, 229, 229, 229, 229, 229, |
|
1125
|
/* 10 */ 229, 229, 229, 229, 229, 229, 229, 229, 229, 229, |
|
1126
|
/* 20 */ 229, 229, 229, 229, 229, 229, 229, 358, 526, 638, |
|
1127
|
/* 30 */ 358, 471, 542, 542, 0, 65, 471, 670, 638, 670, |
|
1128
|
/* 40 */ 504, 504, 504, 574, 600, 638, 638, 638, 638, 638, |
|
1129
|
/* 50 */ 638, 696, 638, 638, 712, 638, 638, 638, 638, 638, |
|
1130
|
/* 60 */ 638, 638, 638, 638, 638, 254, 162, 162, 162, 162, |
|
1131
|
/* 70 */ 162, 435, 263, 332, 401, 464, 464, 205, 48, 1305, |
|
1132
|
/* 80 */ 1305, 1305, 1305, 132, 132, 528, 578, 62, 131, 341, |
|
1133
|
/* 90 */ 423, 293, 7, 469, 622, 698, 792, 777, 884, 506, |
|
1134
|
/* 100 */ 506, 506, 63, 506, 506, 506, 831, 506, 327, 103, |
|
1135
|
/* 110 */ 174, 187, 6, 66, 141, 236, 236, 244, 250, 140, |
|
1136
|
/* 120 */ 211, 381, 147, 178, 203, 216, 212, 219, 206, 223, |
|
1137
|
/* 130 */ 231, 238, 234, 274, 284, 278, 257, 324, 279, 281, |
|
1138
|
/* 140 */ 290, 294, 373, 380, 383, 345, 386, 387, 389, 301, |
|
1139
|
/* 150 */ 321, 377, 301, 399, 400, 403, 406, 396, 402, 407, |
|
1140
|
/* 160 */ 404, 344, 436, 427, |
|
1141
|
}; |
|
1142
|
#define YY_REDUCE_COUNT (82) |
|
1143
|
#define YY_REDUCE_MIN (-132) |
|
1144
|
#define YY_REDUCE_MAX (1167) |
|
1145
|
static const short yy_reduce_ofst[] = { |
|
1146
|
/* 0 */ -76, -98, -33, 35, 176, 213, 280, 451, 633, 709, |
|
1147
|
/* 10 */ 714, 728, 747, 761, 766, 780, 805, 820, 834, 847, |
|
1148
|
/* 20 */ 861, 874, 888, 913, 926, 940, 953, 54, 340, 967, |
|
1149
|
/* 30 */ 305, -11, 539, 620, 76, 76, 249, 639, 455, 572, |
|
1150
|
/* 40 */ 251, 656, 695, 732, 976, 990, 994, 1003, 1019, 1027, |
|
1151
|
/* 50 */ 1032, 1046, 1055, 1061, 1069, 1084, 1092, 1097, 1100, 1125, |
|
1152
|
/* 60 */ 1128, 1133, 1141, 1164, 1167, 82, -114, -39, -20, 30, |
|
1153
|
/* 70 */ 169, 83, -132, -132, -132, -99, -77, -62, -40, 25, |
|
1154
|
/* 80 */ 40, 59, 80, |
|
1155
|
}; |
|
1156
|
static const YYACTIONTYPE yy_default[] = { |
|
1157
|
/* 0 */ 449, 443, 443, 443, 443, 443, 443, 443, 443, 443, |
|
1158
|
/* 10 */ 443, 443, 443, 443, 443, 443, 443, 443, 443, 443, |
|
1159
|
/* 20 */ 443, 443, 443, 443, 443, 443, 443, 443, 473, 576, |
|
1160
|
/* 30 */ 443, 449, 580, 485, 581, 581, 449, 443, 443, 443, |
|
1161
|
/* 40 */ 443, 443, 443, 443, 443, 443, 443, 443, 477, 443, |
|
1162
|
/* 50 */ 443, 443, 443, 443, 443, 443, 443, 443, 443, 443, |
|
1163
|
/* 60 */ 443, 443, 443, 443, 443, 443, 443, 443, 443, 443, |
|
1164
|
/* 70 */ 443, 443, 443, 443, 443, 443, 443, 443, 455, 470, |
|
1165
|
/* 80 */ 508, 508, 576, 468, 493, 443, 443, 443, 471, 443, |
|
1166
|
/* 90 */ 443, 443, 443, 443, 443, 443, 443, 443, 443, 488, |
|
1167
|
/* 100 */ 486, 476, 459, 512, 511, 510, 443, 566, 443, 443, |
|
1168
|
/* 110 */ 443, 443, 443, 588, 443, 545, 544, 540, 443, 532, |
|
1169
|
/* 120 */ 529, 443, 443, 443, 443, 443, 443, 491, 443, 443, |
|
1170
|
/* 130 */ 443, 443, 443, 443, 443, 443, 443, 443, 443, 443, |
|
1171
|
/* 140 */ 443, 443, 443, 443, 443, 443, 443, 443, 443, 592, |
|
1172
|
/* 150 */ 443, 443, 443, 443, 443, 443, 443, 443, 443, 443, |
|
1173
|
/* 160 */ 443, 601, 443, 443, |
|
1174
|
}; |
|
1175
|
/********** End of lemon-generated parsing tables *****************************/ |
|
1176
|
|
|
1177
|
/* The next table maps tokens (terminal symbols) into fallback tokens. |
|
1178
|
** If a construct like the following: |
|
1179
|
** |
|
1180
|
** %fallback ID X Y Z. |
|
1181
|
** |
|
1182
|
** appears in the grammar, then ID becomes a fallback token for X, Y, |
|
1183
|
** and Z. Whenever one of the tokens X, Y, or Z is input to the parser |
|
1184
|
** but it does not parse, the type of the token is changed to ID and |
|
1185
|
** the parse is retried before an error is thrown. |
|
1186
|
** |
|
1187
|
** This feature can be used, for example, to cause some keywords in a language |
|
1188
|
** to revert to identifiers if they keyword does not apply in the context where |
|
1189
|
** it appears. |
|
1190
|
*/ |
|
1191
|
#ifdef YYFALLBACK |
|
1192
|
static const YYCODETYPE yyFallback[] = { |
|
1193
|
0, /* $ => nothing */ |
|
1194
|
0, /* ID => nothing */ |
|
1195
|
1, /* EDGEPT => ID */ |
|
1196
|
0, /* OF => nothing */ |
|
1197
|
0, /* PLUS => nothing */ |
|
1198
|
0, /* MINUS => nothing */ |
|
1199
|
0, /* STAR => nothing */ |
|
1200
|
0, /* SLASH => nothing */ |
|
1201
|
0, /* PERCENT => nothing */ |
|
1202
|
0, /* UMINUS => nothing */ |
|
1203
|
0, /* EOL => nothing */ |
|
1204
|
0, /* ASSIGN => nothing */ |
|
1205
|
0, /* PLACENAME => nothing */ |
|
1206
|
0, /* COLON => nothing */ |
|
1207
|
0, /* ASSERT => nothing */ |
|
1208
|
0, /* LP => nothing */ |
|
1209
|
0, /* EQ => nothing */ |
|
1210
|
0, /* RP => nothing */ |
|
1211
|
0, /* DEFINE => nothing */ |
|
1212
|
0, /* CODEBLOCK => nothing */ |
|
1213
|
0, /* FILL => nothing */ |
|
1214
|
0, /* COLOR => nothing */ |
|
1215
|
0, /* THICKNESS => nothing */ |
|
1216
|
0, /* PRINT => nothing */ |
|
1217
|
0, /* STRING => nothing */ |
|
1218
|
0, /* COMMA => nothing */ |
|
1219
|
0, /* ISODATE => nothing */ |
|
1220
|
0, /* CLASSNAME => nothing */ |
|
1221
|
0, /* LB => nothing */ |
|
1222
|
0, /* RB => nothing */ |
|
1223
|
0, /* UP => nothing */ |
|
1224
|
0, /* DOWN => nothing */ |
|
1225
|
0, /* LEFT => nothing */ |
|
1226
|
0, /* RIGHT => nothing */ |
|
1227
|
0, /* CLOSE => nothing */ |
|
1228
|
0, /* CHOP => nothing */ |
|
1229
|
0, /* FROM => nothing */ |
|
1230
|
0, /* TO => nothing */ |
|
1231
|
0, /* THEN => nothing */ |
|
1232
|
0, /* HEADING => nothing */ |
|
1233
|
0, /* GO => nothing */ |
|
1234
|
0, /* AT => nothing */ |
|
1235
|
0, /* WITH => nothing */ |
|
1236
|
0, /* SAME => nothing */ |
|
1237
|
0, /* AS => nothing */ |
|
1238
|
0, /* FIT => nothing */ |
|
1239
|
0, /* BEHIND => nothing */ |
|
1240
|
0, /* UNTIL => nothing */ |
|
1241
|
0, /* EVEN => nothing */ |
|
1242
|
0, /* DOT_E => nothing */ |
|
1243
|
0, /* HEIGHT => nothing */ |
|
1244
|
0, /* WIDTH => nothing */ |
|
1245
|
0, /* RADIUS => nothing */ |
|
1246
|
0, /* DIAMETER => nothing */ |
|
1247
|
0, /* DOTTED => nothing */ |
|
1248
|
0, /* DASHED => nothing */ |
|
1249
|
0, /* CW => nothing */ |
|
1250
|
0, /* CCW => nothing */ |
|
1251
|
0, /* LARROW => nothing */ |
|
1252
|
0, /* RARROW => nothing */ |
|
1253
|
0, /* LRARROW => nothing */ |
|
1254
|
0, /* INVIS => nothing */ |
|
1255
|
0, /* THICK => nothing */ |
|
1256
|
0, /* THIN => nothing */ |
|
1257
|
0, /* SOLID => nothing */ |
|
1258
|
0, /* CENTER => nothing */ |
|
1259
|
0, /* LJUST => nothing */ |
|
1260
|
0, /* RJUST => nothing */ |
|
1261
|
0, /* ABOVE => nothing */ |
|
1262
|
0, /* BELOW => nothing */ |
|
1263
|
0, /* ITALIC => nothing */ |
|
1264
|
0, /* BOLD => nothing */ |
|
1265
|
0, /* MONO => nothing */ |
|
1266
|
0, /* ALIGNED => nothing */ |
|
1267
|
0, /* BIG => nothing */ |
|
1268
|
0, /* SMALL => nothing */ |
|
1269
|
0, /* AND => nothing */ |
|
1270
|
0, /* LT => nothing */ |
|
1271
|
0, /* GT => nothing */ |
|
1272
|
0, /* ON => nothing */ |
|
1273
|
0, /* WAY => nothing */ |
|
1274
|
0, /* BETWEEN => nothing */ |
|
1275
|
0, /* THE => nothing */ |
|
1276
|
0, /* NTH => nothing */ |
|
1277
|
0, /* VERTEX => nothing */ |
|
1278
|
0, /* TOP => nothing */ |
|
1279
|
0, /* BOTTOM => nothing */ |
|
1280
|
0, /* START => nothing */ |
|
1281
|
0, /* END => nothing */ |
|
1282
|
0, /* IN => nothing */ |
|
1283
|
0, /* THIS => nothing */ |
|
1284
|
0, /* DOT_U => nothing */ |
|
1285
|
0, /* LAST => nothing */ |
|
1286
|
0, /* NUMBER => nothing */ |
|
1287
|
0, /* FUNC1 => nothing */ |
|
1288
|
0, /* FUNC2 => nothing */ |
|
1289
|
0, /* DIST => nothing */ |
|
1290
|
0, /* DOT_XY => nothing */ |
|
1291
|
0, /* X => nothing */ |
|
1292
|
0, /* Y => nothing */ |
|
1293
|
0, /* DOT_L => nothing */ |
|
1294
|
}; |
|
1295
|
#endif /* YYFALLBACK */ |
|
1296
|
|
|
1297
|
/* The following structure represents a single element of the |
|
1298
|
** parser's stack. Information stored includes: |
|
1299
|
** |
|
1300
|
** + The state number for the parser at this level of the stack. |
|
1301
|
** |
|
1302
|
** + The value of the token stored at this level of the stack. |
|
1303
|
** (In other words, the "major" token.) |
|
1304
|
** |
|
1305
|
** + The semantic value stored at this level of the stack. This is |
|
1306
|
** the information used by the action routines in the grammar. |
|
1307
|
** It is sometimes called the "minor" token. |
|
1308
|
** |
|
1309
|
** After the "shift" half of a SHIFTREDUCE action, the stateno field |
|
1310
|
** actually contains the reduce action for the second half of the |
|
1311
|
** SHIFTREDUCE. |
|
1312
|
*/ |
|
1313
|
struct yyStackEntry { |
|
1314
|
YYACTIONTYPE stateno; /* The state-number, or reduce action in SHIFTREDUCE */ |
|
1315
|
YYCODETYPE major; /* The major token value. This is the code |
|
1316
|
** number for the token at this stack level */ |
|
1317
|
YYMINORTYPE minor; /* The user-supplied minor token value. This |
|
1318
|
** is the value of the token */ |
|
1319
|
}; |
|
1320
|
typedef struct yyStackEntry yyStackEntry; |
|
1321
|
|
|
1322
|
/* The state of the parser is completely contained in an instance of |
|
1323
|
** the following structure */ |
|
1324
|
struct yyParser { |
|
1325
|
yyStackEntry *yytos; /* Pointer to top element of the stack */ |
|
1326
|
#ifdef YYTRACKMAXSTACKDEPTH |
|
1327
|
int yyhwm; /* High-water mark of the stack */ |
|
1328
|
#endif |
|
1329
|
#ifndef YYNOERRORRECOVERY |
|
1330
|
int yyerrcnt; /* Shifts left before out of the error */ |
|
1331
|
#endif |
|
1332
|
pik_parserARG_SDECL /* A place to hold %extra_argument */ |
|
1333
|
pik_parserCTX_SDECL /* A place to hold %extra_context */ |
|
1334
|
yyStackEntry *yystackEnd; /* Last entry in the stack */ |
|
1335
|
yyStackEntry *yystack; /* The parser stack */ |
|
1336
|
yyStackEntry yystk0[YYSTACKDEPTH]; /* Initial stack space */ |
|
1337
|
}; |
|
1338
|
typedef struct yyParser yyParser; |
|
1339
|
|
|
1340
|
#include <assert.h> |
|
1341
|
#ifndef NDEBUG |
|
1342
|
#include <stdio.h> |
|
1343
|
static FILE *yyTraceFILE = 0; |
|
1344
|
static char *yyTracePrompt = 0; |
|
1345
|
#endif /* NDEBUG */ |
|
1346
|
|
|
1347
|
#ifndef NDEBUG |
|
1348
|
/* |
|
1349
|
** Turn parser tracing on by giving a stream to which to write the trace |
|
1350
|
** and a prompt to preface each trace message. Tracing is turned off |
|
1351
|
** by making either argument NULL |
|
1352
|
** |
|
1353
|
** Inputs: |
|
1354
|
** <ul> |
|
1355
|
** <li> A FILE* to which trace output should be written. |
|
1356
|
** If NULL, then tracing is turned off. |
|
1357
|
** <li> A prefix string written at the beginning of every |
|
1358
|
** line of trace output. If NULL, then tracing is |
|
1359
|
** turned off. |
|
1360
|
** </ul> |
|
1361
|
** |
|
1362
|
** Outputs: |
|
1363
|
** None. |
|
1364
|
*/ |
|
1365
|
void pik_parserTrace(FILE *TraceFILE, char *zTracePrompt){ |
|
1366
|
yyTraceFILE = TraceFILE; |
|
1367
|
yyTracePrompt = zTracePrompt; |
|
1368
|
if( yyTraceFILE==0 ) yyTracePrompt = 0; |
|
1369
|
else if( yyTracePrompt==0 ) yyTraceFILE = 0; |
|
1370
|
} |
|
1371
|
#endif /* NDEBUG */ |
|
1372
|
|
|
1373
|
#if defined(YYCOVERAGE) || !defined(NDEBUG) |
|
1374
|
/* For tracing shifts, the names of all terminals and nonterminals |
|
1375
|
** are required. The following table supplies these names */ |
|
1376
|
static const char *const yyTokenName[] = { |
|
1377
|
/* 0 */ "$", |
|
1378
|
/* 1 */ "ID", |
|
1379
|
/* 2 */ "EDGEPT", |
|
1380
|
/* 3 */ "OF", |
|
1381
|
/* 4 */ "PLUS", |
|
1382
|
/* 5 */ "MINUS", |
|
1383
|
/* 6 */ "STAR", |
|
1384
|
/* 7 */ "SLASH", |
|
1385
|
/* 8 */ "PERCENT", |
|
1386
|
/* 9 */ "UMINUS", |
|
1387
|
/* 10 */ "EOL", |
|
1388
|
/* 11 */ "ASSIGN", |
|
1389
|
/* 12 */ "PLACENAME", |
|
1390
|
/* 13 */ "COLON", |
|
1391
|
/* 14 */ "ASSERT", |
|
1392
|
/* 15 */ "LP", |
|
1393
|
/* 16 */ "EQ", |
|
1394
|
/* 17 */ "RP", |
|
1395
|
/* 18 */ "DEFINE", |
|
1396
|
/* 19 */ "CODEBLOCK", |
|
1397
|
/* 20 */ "FILL", |
|
1398
|
/* 21 */ "COLOR", |
|
1399
|
/* 22 */ "THICKNESS", |
|
1400
|
/* 23 */ "PRINT", |
|
1401
|
/* 24 */ "STRING", |
|
1402
|
/* 25 */ "COMMA", |
|
1403
|
/* 26 */ "ISODATE", |
|
1404
|
/* 27 */ "CLASSNAME", |
|
1405
|
/* 28 */ "LB", |
|
1406
|
/* 29 */ "RB", |
|
1407
|
/* 30 */ "UP", |
|
1408
|
/* 31 */ "DOWN", |
|
1409
|
/* 32 */ "LEFT", |
|
1410
|
/* 33 */ "RIGHT", |
|
1411
|
/* 34 */ "CLOSE", |
|
1412
|
/* 35 */ "CHOP", |
|
1413
|
/* 36 */ "FROM", |
|
1414
|
/* 37 */ "TO", |
|
1415
|
/* 38 */ "THEN", |
|
1416
|
/* 39 */ "HEADING", |
|
1417
|
/* 40 */ "GO", |
|
1418
|
/* 41 */ "AT", |
|
1419
|
/* 42 */ "WITH", |
|
1420
|
/* 43 */ "SAME", |
|
1421
|
/* 44 */ "AS", |
|
1422
|
/* 45 */ "FIT", |
|
1423
|
/* 46 */ "BEHIND", |
|
1424
|
/* 47 */ "UNTIL", |
|
1425
|
/* 48 */ "EVEN", |
|
1426
|
/* 49 */ "DOT_E", |
|
1427
|
/* 50 */ "HEIGHT", |
|
1428
|
/* 51 */ "WIDTH", |
|
1429
|
/* 52 */ "RADIUS", |
|
1430
|
/* 53 */ "DIAMETER", |
|
1431
|
/* 54 */ "DOTTED", |
|
1432
|
/* 55 */ "DASHED", |
|
1433
|
/* 56 */ "CW", |
|
1434
|
/* 57 */ "CCW", |
|
1435
|
/* 58 */ "LARROW", |
|
1436
|
/* 59 */ "RARROW", |
|
1437
|
/* 60 */ "LRARROW", |
|
1438
|
/* 61 */ "INVIS", |
|
1439
|
/* 62 */ "THICK", |
|
1440
|
/* 63 */ "THIN", |
|
1441
|
/* 64 */ "SOLID", |
|
1442
|
/* 65 */ "CENTER", |
|
1443
|
/* 66 */ "LJUST", |
|
1444
|
/* 67 */ "RJUST", |
|
1445
|
/* 68 */ "ABOVE", |
|
1446
|
/* 69 */ "BELOW", |
|
1447
|
/* 70 */ "ITALIC", |
|
1448
|
/* 71 */ "BOLD", |
|
1449
|
/* 72 */ "MONO", |
|
1450
|
/* 73 */ "ALIGNED", |
|
1451
|
/* 74 */ "BIG", |
|
1452
|
/* 75 */ "SMALL", |
|
1453
|
/* 76 */ "AND", |
|
1454
|
/* 77 */ "LT", |
|
1455
|
/* 78 */ "GT", |
|
1456
|
/* 79 */ "ON", |
|
1457
|
/* 80 */ "WAY", |
|
1458
|
/* 81 */ "BETWEEN", |
|
1459
|
/* 82 */ "THE", |
|
1460
|
/* 83 */ "NTH", |
|
1461
|
/* 84 */ "VERTEX", |
|
1462
|
/* 85 */ "TOP", |
|
1463
|
/* 86 */ "BOTTOM", |
|
1464
|
/* 87 */ "START", |
|
1465
|
/* 88 */ "END", |
|
1466
|
/* 89 */ "IN", |
|
1467
|
/* 90 */ "THIS", |
|
1468
|
/* 91 */ "DOT_U", |
|
1469
|
/* 92 */ "LAST", |
|
1470
|
/* 93 */ "NUMBER", |
|
1471
|
/* 94 */ "FUNC1", |
|
1472
|
/* 95 */ "FUNC2", |
|
1473
|
/* 96 */ "DIST", |
|
1474
|
/* 97 */ "DOT_XY", |
|
1475
|
/* 98 */ "X", |
|
1476
|
/* 99 */ "Y", |
|
1477
|
/* 100 */ "DOT_L", |
|
1478
|
/* 101 */ "statement_list", |
|
1479
|
/* 102 */ "statement", |
|
1480
|
/* 103 */ "unnamed_statement", |
|
1481
|
/* 104 */ "basetype", |
|
1482
|
/* 105 */ "expr", |
|
1483
|
/* 106 */ "numproperty", |
|
1484
|
/* 107 */ "edge", |
|
1485
|
/* 108 */ "isodate", |
|
1486
|
/* 109 */ "direction", |
|
1487
|
/* 110 */ "dashproperty", |
|
1488
|
/* 111 */ "colorproperty", |
|
1489
|
/* 112 */ "locproperty", |
|
1490
|
/* 113 */ "position", |
|
1491
|
/* 114 */ "place", |
|
1492
|
/* 115 */ "object", |
|
1493
|
/* 116 */ "objectname", |
|
1494
|
/* 117 */ "nth", |
|
1495
|
/* 118 */ "textposition", |
|
1496
|
/* 119 */ "rvalue", |
|
1497
|
/* 120 */ "lvalue", |
|
1498
|
/* 121 */ "even", |
|
1499
|
/* 122 */ "relexpr", |
|
1500
|
/* 123 */ "optrelexpr", |
|
1501
|
/* 124 */ "document", |
|
1502
|
/* 125 */ "print", |
|
1503
|
/* 126 */ "prlist", |
|
1504
|
/* 127 */ "pritem", |
|
1505
|
/* 128 */ "prsep", |
|
1506
|
/* 129 */ "attribute_list", |
|
1507
|
/* 130 */ "savelist", |
|
1508
|
/* 131 */ "alist", |
|
1509
|
/* 132 */ "attribute", |
|
1510
|
/* 133 */ "go", |
|
1511
|
/* 134 */ "boolproperty", |
|
1512
|
/* 135 */ "withclause", |
|
1513
|
/* 136 */ "between", |
|
1514
|
/* 137 */ "place2", |
|
1515
|
}; |
|
1516
|
#endif /* defined(YYCOVERAGE) || !defined(NDEBUG) */ |
|
1517
|
|
|
1518
|
#ifndef NDEBUG |
|
1519
|
/* For tracing reduce actions, the names of all rules are required. |
|
1520
|
*/ |
|
1521
|
static const char *const yyRuleName[] = { |
|
1522
|
/* 0 */ "document ::= statement_list", |
|
1523
|
/* 1 */ "statement_list ::= statement", |
|
1524
|
/* 2 */ "statement_list ::= statement_list EOL statement", |
|
1525
|
/* 3 */ "statement ::=", |
|
1526
|
/* 4 */ "statement ::= direction", |
|
1527
|
/* 5 */ "statement ::= lvalue ASSIGN rvalue", |
|
1528
|
/* 6 */ "statement ::= PLACENAME COLON unnamed_statement", |
|
1529
|
/* 7 */ "statement ::= PLACENAME COLON position", |
|
1530
|
/* 8 */ "statement ::= unnamed_statement", |
|
1531
|
/* 9 */ "statement ::= print prlist", |
|
1532
|
/* 10 */ "statement ::= ASSERT LP expr EQ expr RP", |
|
1533
|
/* 11 */ "statement ::= ASSERT LP position EQ position RP", |
|
1534
|
/* 12 */ "statement ::= DEFINE ID CODEBLOCK", |
|
1535
|
/* 13 */ "rvalue ::= PLACENAME", |
|
1536
|
/* 14 */ "pritem ::= FILL", |
|
1537
|
/* 15 */ "pritem ::= COLOR", |
|
1538
|
/* 16 */ "pritem ::= THICKNESS", |
|
1539
|
/* 17 */ "pritem ::= rvalue", |
|
1540
|
/* 18 */ "pritem ::= STRING", |
|
1541
|
/* 19 */ "prsep ::= COMMA", |
|
1542
|
/* 20 */ "unnamed_statement ::= basetype attribute_list", |
|
1543
|
/* 21 */ "basetype ::= CLASSNAME", |
|
1544
|
/* 22 */ "basetype ::= STRING textposition", |
|
1545
|
/* 23 */ "basetype ::= LB savelist statement_list RB", |
|
1546
|
/* 24 */ "savelist ::=", |
|
1547
|
/* 25 */ "relexpr ::= expr", |
|
1548
|
/* 26 */ "relexpr ::= expr PERCENT", |
|
1549
|
/* 27 */ "optrelexpr ::=", |
|
1550
|
/* 28 */ "attribute_list ::= relexpr alist", |
|
1551
|
/* 29 */ "attribute ::= numproperty relexpr", |
|
1552
|
/* 30 */ "attribute ::= dashproperty expr", |
|
1553
|
/* 31 */ "attribute ::= dashproperty", |
|
1554
|
/* 32 */ "attribute ::= colorproperty rvalue", |
|
1555
|
/* 33 */ "attribute ::= go direction optrelexpr", |
|
1556
|
/* 34 */ "attribute ::= go direction even position", |
|
1557
|
/* 35 */ "attribute ::= CLOSE", |
|
1558
|
/* 36 */ "attribute ::= CHOP", |
|
1559
|
/* 37 */ "attribute ::= FROM position", |
|
1560
|
/* 38 */ "attribute ::= TO position", |
|
1561
|
/* 39 */ "attribute ::= THEN", |
|
1562
|
/* 40 */ "attribute ::= THEN optrelexpr HEADING expr", |
|
1563
|
/* 41 */ "attribute ::= THEN optrelexpr EDGEPT", |
|
1564
|
/* 42 */ "attribute ::= GO optrelexpr HEADING expr", |
|
1565
|
/* 43 */ "attribute ::= GO optrelexpr EDGEPT", |
|
1566
|
/* 44 */ "attribute ::= AT position", |
|
1567
|
/* 45 */ "attribute ::= SAME", |
|
1568
|
/* 46 */ "attribute ::= SAME AS object", |
|
1569
|
/* 47 */ "attribute ::= STRING textposition", |
|
1570
|
/* 48 */ "attribute ::= FIT", |
|
1571
|
/* 49 */ "attribute ::= BEHIND object", |
|
1572
|
/* 50 */ "withclause ::= DOT_E edge AT position", |
|
1573
|
/* 51 */ "withclause ::= edge AT position", |
|
1574
|
/* 52 */ "numproperty ::= HEIGHT|WIDTH|RADIUS|DIAMETER|THICKNESS", |
|
1575
|
/* 53 */ "boolproperty ::= CW", |
|
1576
|
/* 54 */ "boolproperty ::= CCW", |
|
1577
|
/* 55 */ "boolproperty ::= LARROW", |
|
1578
|
/* 56 */ "boolproperty ::= RARROW", |
|
1579
|
/* 57 */ "boolproperty ::= LRARROW", |
|
1580
|
/* 58 */ "boolproperty ::= INVIS", |
|
1581
|
/* 59 */ "boolproperty ::= THICK", |
|
1582
|
/* 60 */ "boolproperty ::= THIN", |
|
1583
|
/* 61 */ "boolproperty ::= SOLID", |
|
1584
|
/* 62 */ "textposition ::=", |
|
1585
|
/* 63 */ "textposition ::= textposition CENTER|LJUST|RJUST|ABOVE|BELOW|ITALIC|BOLD|MONO|ALIGNED|BIG|SMALL", |
|
1586
|
/* 64 */ "position ::= expr COMMA expr", |
|
1587
|
/* 65 */ "position ::= place PLUS expr COMMA expr", |
|
1588
|
/* 66 */ "position ::= place MINUS expr COMMA expr", |
|
1589
|
/* 67 */ "position ::= place PLUS LP expr COMMA expr RP", |
|
1590
|
/* 68 */ "position ::= place MINUS LP expr COMMA expr RP", |
|
1591
|
/* 69 */ "position ::= LP position COMMA position RP", |
|
1592
|
/* 70 */ "position ::= LP position RP", |
|
1593
|
/* 71 */ "position ::= expr between position AND position", |
|
1594
|
/* 72 */ "position ::= expr LT position COMMA position GT", |
|
1595
|
/* 73 */ "position ::= expr ABOVE position", |
|
1596
|
/* 74 */ "position ::= expr BELOW position", |
|
1597
|
/* 75 */ "position ::= expr LEFT OF position", |
|
1598
|
/* 76 */ "position ::= expr RIGHT OF position", |
|
1599
|
/* 77 */ "position ::= expr ON HEADING EDGEPT OF position", |
|
1600
|
/* 78 */ "position ::= expr HEADING EDGEPT OF position", |
|
1601
|
/* 79 */ "position ::= expr EDGEPT OF position", |
|
1602
|
/* 80 */ "position ::= expr ON HEADING expr FROM position", |
|
1603
|
/* 81 */ "position ::= expr HEADING expr FROM position", |
|
1604
|
/* 82 */ "place ::= edge OF object", |
|
1605
|
/* 83 */ "place2 ::= object", |
|
1606
|
/* 84 */ "place2 ::= object DOT_E edge", |
|
1607
|
/* 85 */ "place2 ::= NTH VERTEX OF object", |
|
1608
|
/* 86 */ "object ::= nth", |
|
1609
|
/* 87 */ "object ::= nth OF|IN object", |
|
1610
|
/* 88 */ "objectname ::= THIS", |
|
1611
|
/* 89 */ "objectname ::= PLACENAME", |
|
1612
|
/* 90 */ "objectname ::= objectname DOT_U PLACENAME", |
|
1613
|
/* 91 */ "nth ::= NTH CLASSNAME", |
|
1614
|
/* 92 */ "nth ::= NTH LAST CLASSNAME", |
|
1615
|
/* 93 */ "nth ::= LAST CLASSNAME", |
|
1616
|
/* 94 */ "nth ::= LAST", |
|
1617
|
/* 95 */ "nth ::= NTH LB RB", |
|
1618
|
/* 96 */ "nth ::= NTH LAST LB RB", |
|
1619
|
/* 97 */ "nth ::= LAST LB RB", |
|
1620
|
/* 98 */ "expr ::= expr PLUS expr", |
|
1621
|
/* 99 */ "expr ::= expr MINUS expr", |
|
1622
|
/* 100 */ "expr ::= expr STAR expr", |
|
1623
|
/* 101 */ "expr ::= expr SLASH expr", |
|
1624
|
/* 102 */ "expr ::= MINUS expr", |
|
1625
|
/* 103 */ "expr ::= PLUS expr", |
|
1626
|
/* 104 */ "expr ::= LP expr RP", |
|
1627
|
/* 105 */ "expr ::= LP FILL|COLOR|THICKNESS RP", |
|
1628
|
/* 106 */ "expr ::= NUMBER", |
|
1629
|
/* 107 */ "expr ::= ID", |
|
1630
|
/* 108 */ "expr ::= FUNC1 LP expr RP", |
|
1631
|
/* 109 */ "expr ::= FUNC2 LP expr COMMA expr RP", |
|
1632
|
/* 110 */ "expr ::= DIST LP position COMMA position RP", |
|
1633
|
/* 111 */ "expr ::= place2 DOT_XY X", |
|
1634
|
/* 112 */ "expr ::= place2 DOT_XY Y", |
|
1635
|
/* 113 */ "expr ::= object DOT_L numproperty", |
|
1636
|
/* 114 */ "expr ::= object DOT_L dashproperty", |
|
1637
|
/* 115 */ "expr ::= object DOT_L colorproperty", |
|
1638
|
/* 116 */ "lvalue ::= ID", |
|
1639
|
/* 117 */ "lvalue ::= FILL", |
|
1640
|
/* 118 */ "lvalue ::= COLOR", |
|
1641
|
/* 119 */ "lvalue ::= THICKNESS", |
|
1642
|
/* 120 */ "rvalue ::= expr", |
|
1643
|
/* 121 */ "print ::= PRINT", |
|
1644
|
/* 122 */ "prlist ::= pritem", |
|
1645
|
/* 123 */ "prlist ::= prlist prsep pritem", |
|
1646
|
/* 124 */ "direction ::= UP", |
|
1647
|
/* 125 */ "direction ::= DOWN", |
|
1648
|
/* 126 */ "direction ::= LEFT", |
|
1649
|
/* 127 */ "direction ::= RIGHT", |
|
1650
|
/* 128 */ "optrelexpr ::= relexpr", |
|
1651
|
/* 129 */ "attribute_list ::= alist", |
|
1652
|
/* 130 */ "alist ::=", |
|
1653
|
/* 131 */ "alist ::= alist attribute", |
|
1654
|
/* 132 */ "attribute ::= boolproperty", |
|
1655
|
/* 133 */ "attribute ::= WITH withclause", |
|
1656
|
/* 134 */ "go ::= GO", |
|
1657
|
/* 135 */ "go ::=", |
|
1658
|
/* 136 */ "even ::= UNTIL EVEN WITH", |
|
1659
|
/* 137 */ "even ::= EVEN WITH", |
|
1660
|
/* 138 */ "dashproperty ::= DOTTED", |
|
1661
|
/* 139 */ "dashproperty ::= DASHED", |
|
1662
|
/* 140 */ "colorproperty ::= FILL", |
|
1663
|
/* 141 */ "colorproperty ::= COLOR", |
|
1664
|
/* 142 */ "position ::= place", |
|
1665
|
/* 143 */ "between ::= WAY BETWEEN", |
|
1666
|
/* 144 */ "between ::= BETWEEN", |
|
1667
|
/* 145 */ "between ::= OF THE WAY BETWEEN", |
|
1668
|
/* 146 */ "place ::= place2", |
|
1669
|
/* 147 */ "edge ::= CENTER", |
|
1670
|
/* 148 */ "edge ::= EDGEPT", |
|
1671
|
/* 149 */ "edge ::= TOP", |
|
1672
|
/* 150 */ "edge ::= BOTTOM", |
|
1673
|
/* 151 */ "edge ::= START", |
|
1674
|
/* 152 */ "edge ::= END", |
|
1675
|
/* 153 */ "edge ::= RIGHT", |
|
1676
|
/* 154 */ "edge ::= LEFT", |
|
1677
|
/* 155 */ "object ::= objectname", |
|
1678
|
}; |
|
1679
|
#endif /* NDEBUG */ |
|
1680
|
|
|
1681
|
|
|
1682
|
#if YYGROWABLESTACK |
|
1683
|
/* |
|
1684
|
** Try to increase the size of the parser stack. Return the number |
|
1685
|
** of errors. Return 0 on success. |
|
1686
|
*/ |
|
1687
|
static int yyGrowStack(yyParser *p){ |
|
1688
|
int oldSize = 1 + (int)(p->yystackEnd - p->yystack); |
|
1689
|
int newSize; |
|
1690
|
int idx; |
|
1691
|
yyStackEntry *pNew; |
|
1692
|
|
|
1693
|
newSize = oldSize*2 + 100; |
|
1694
|
idx = (int)(p->yytos - p->yystack); |
|
1695
|
if( p->yystack==p->yystk0 ){ |
|
1696
|
pNew = YYREALLOC(0, newSize*sizeof(pNew[0])); |
|
1697
|
if( pNew==0 ) return 1; |
|
1698
|
memcpy(pNew, p->yystack, oldSize*sizeof(pNew[0])); |
|
1699
|
}else{ |
|
1700
|
pNew = YYREALLOC(p->yystack, newSize*sizeof(pNew[0])); |
|
1701
|
if( pNew==0 ) return 1; |
|
1702
|
} |
|
1703
|
p->yystack = pNew; |
|
1704
|
p->yytos = &p->yystack[idx]; |
|
1705
|
#ifndef NDEBUG |
|
1706
|
if( yyTraceFILE ){ |
|
1707
|
fprintf(yyTraceFILE,"%sStack grows from %d to %d entries.\n", |
|
1708
|
yyTracePrompt, oldSize, newSize); |
|
1709
|
} |
|
1710
|
#endif |
|
1711
|
p->yystackEnd = &p->yystack[newSize-1]; |
|
1712
|
return 0; |
|
1713
|
} |
|
1714
|
#endif /* YYGROWABLESTACK */ |
|
1715
|
|
|
1716
|
#if !YYGROWABLESTACK |
|
1717
|
/* For builds that do no have a growable stack, yyGrowStack always |
|
1718
|
** returns an error. |
|
1719
|
*/ |
|
1720
|
# define yyGrowStack(X) 1 |
|
1721
|
#endif |
|
1722
|
|
|
1723
|
/* Datatype of the argument to the memory allocated passed as the |
|
1724
|
** second argument to pik_parserAlloc() below. This can be changed by |
|
1725
|
** putting an appropriate #define in the %include section of the input |
|
1726
|
** grammar. |
|
1727
|
*/ |
|
1728
|
#ifndef YYMALLOCARGTYPE |
|
1729
|
# define YYMALLOCARGTYPE size_t |
|
1730
|
#endif |
|
1731
|
|
|
1732
|
/* Initialize a new parser that has already been allocated. |
|
1733
|
*/ |
|
1734
|
void pik_parserInit(void *yypRawParser pik_parserCTX_PDECL){ |
|
1735
|
yyParser *yypParser = (yyParser*)yypRawParser; |
|
1736
|
pik_parserCTX_STORE |
|
1737
|
#ifdef YYTRACKMAXSTACKDEPTH |
|
1738
|
yypParser->yyhwm = 0; |
|
1739
|
#endif |
|
1740
|
yypParser->yystack = yypParser->yystk0; |
|
1741
|
yypParser->yystackEnd = &yypParser->yystack[YYSTACKDEPTH-1]; |
|
1742
|
#ifndef YYNOERRORRECOVERY |
|
1743
|
yypParser->yyerrcnt = -1; |
|
1744
|
#endif |
|
1745
|
yypParser->yytos = yypParser->yystack; |
|
1746
|
yypParser->yystack[0].stateno = 0; |
|
1747
|
yypParser->yystack[0].major = 0; |
|
1748
|
} |
|
1749
|
|
|
1750
|
#ifndef pik_parser_ENGINEALWAYSONSTACK |
|
1751
|
/* |
|
1752
|
** This function allocates a new parser. |
|
1753
|
** The only argument is a pointer to a function which works like |
|
1754
|
** malloc. |
|
1755
|
** |
|
1756
|
** Inputs: |
|
1757
|
** A pointer to the function used to allocate memory. |
|
1758
|
** |
|
1759
|
** Outputs: |
|
1760
|
** A pointer to a parser. This pointer is used in subsequent calls |
|
1761
|
** to pik_parser and pik_parserFree. |
|
1762
|
*/ |
|
1763
|
void *pik_parserAlloc(void *(*mallocProc)(YYMALLOCARGTYPE) pik_parserCTX_PDECL){ |
|
1764
|
yyParser *yypParser; |
|
1765
|
yypParser = (yyParser*)(*mallocProc)( (YYMALLOCARGTYPE)sizeof(yyParser) ); |
|
1766
|
if( yypParser ){ |
|
1767
|
pik_parserCTX_STORE |
|
1768
|
pik_parserInit(yypParser pik_parserCTX_PARAM); |
|
1769
|
} |
|
1770
|
return (void*)yypParser; |
|
1771
|
} |
|
1772
|
#endif /* pik_parser_ENGINEALWAYSONSTACK */ |
|
1773
|
|
|
1774
|
|
|
1775
|
/* The following function deletes the "minor type" or semantic value |
|
1776
|
** associated with a symbol. The symbol can be either a terminal |
|
1777
|
** or nonterminal. "yymajor" is the symbol code, and "yypminor" is |
|
1778
|
** a pointer to the value to be deleted. The code used to do the |
|
1779
|
** deletions is derived from the %destructor and/or %token_destructor |
|
1780
|
** directives of the input grammar. |
|
1781
|
*/ |
|
1782
|
static void yy_destructor( |
|
1783
|
yyParser *yypParser, /* The parser */ |
|
1784
|
YYCODETYPE yymajor, /* Type code for object to destroy */ |
|
1785
|
YYMINORTYPE *yypminor /* The object to be destroyed */ |
|
1786
|
){ |
|
1787
|
pik_parserARG_FETCH |
|
1788
|
pik_parserCTX_FETCH |
|
1789
|
switch( yymajor ){ |
|
1790
|
/* Here is inserted the actions which take place when a |
|
1791
|
** terminal or non-terminal is destroyed. This can happen |
|
1792
|
** when the symbol is popped from the stack during a |
|
1793
|
** reduce or during error processing or when a parser is |
|
1794
|
** being destroyed before it is finished parsing. |
|
1795
|
** |
|
1796
|
** Note: during a reduce, the only symbols destroyed are those |
|
1797
|
** which appear on the RHS of the rule, but which are *not* used |
|
1798
|
** inside the C code. |
|
1799
|
*/ |
|
1800
|
/********* Begin destructor definitions ***************************************/ |
|
1801
|
case 101: /* statement_list */ |
|
1802
|
{ |
|
1803
|
#line 524 "pikchr.y" |
|
1804
|
pik_elist_free(p,(yypminor->yy23)); |
|
1805
|
#line 1805 "pikchr.c" |
|
1806
|
} |
|
1807
|
break; |
|
1808
|
case 102: /* statement */ |
|
1809
|
case 103: /* unnamed_statement */ |
|
1810
|
case 104: /* basetype */ |
|
1811
|
{ |
|
1812
|
#line 526 "pikchr.y" |
|
1813
|
pik_elem_free(p,(yypminor->yy54)); |
|
1814
|
#line 1814 "pikchr.c" |
|
1815
|
} |
|
1816
|
break; |
|
1817
|
/********* End destructor definitions *****************************************/ |
|
1818
|
default: break; /* If no destructor action specified: do nothing */ |
|
1819
|
} |
|
1820
|
} |
|
1821
|
|
|
1822
|
/* |
|
1823
|
** Pop the parser's stack once. |
|
1824
|
** |
|
1825
|
** If there is a destructor routine associated with the token which |
|
1826
|
** is popped from the stack, then call it. |
|
1827
|
*/ |
|
1828
|
static void yy_pop_parser_stack(yyParser *pParser){ |
|
1829
|
yyStackEntry *yytos; |
|
1830
|
assert( pParser->yytos!=0 ); |
|
1831
|
assert( pParser->yytos > pParser->yystack ); |
|
1832
|
yytos = pParser->yytos--; |
|
1833
|
#ifndef NDEBUG |
|
1834
|
if( yyTraceFILE ){ |
|
1835
|
fprintf(yyTraceFILE,"%sPopping %s\n", |
|
1836
|
yyTracePrompt, |
|
1837
|
yyTokenName[yytos->major]); |
|
1838
|
} |
|
1839
|
#endif |
|
1840
|
yy_destructor(pParser, yytos->major, &yytos->minor); |
|
1841
|
} |
|
1842
|
|
|
1843
|
/* |
|
1844
|
** Clear all secondary memory allocations from the parser |
|
1845
|
*/ |
|
1846
|
void pik_parserFinalize(void *p){ |
|
1847
|
yyParser *pParser = (yyParser*)p; |
|
1848
|
|
|
1849
|
/* In-lined version of calling yy_pop_parser_stack() for each |
|
1850
|
** element left in the stack */ |
|
1851
|
yyStackEntry *yytos = pParser->yytos; |
|
1852
|
while( yytos>pParser->yystack ){ |
|
1853
|
#ifndef NDEBUG |
|
1854
|
if( yyTraceFILE ){ |
|
1855
|
fprintf(yyTraceFILE,"%sPopping %s\n", |
|
1856
|
yyTracePrompt, |
|
1857
|
yyTokenName[yytos->major]); |
|
1858
|
} |
|
1859
|
#endif |
|
1860
|
if( yytos->major>=YY_MIN_DSTRCTR ){ |
|
1861
|
yy_destructor(pParser, yytos->major, &yytos->minor); |
|
1862
|
} |
|
1863
|
yytos--; |
|
1864
|
} |
|
1865
|
|
|
1866
|
#if YYGROWABLESTACK |
|
1867
|
if( pParser->yystack!=pParser->yystk0 ) YYFREE(pParser->yystack); |
|
1868
|
#endif |
|
1869
|
} |
|
1870
|
|
|
1871
|
#ifndef pik_parser_ENGINEALWAYSONSTACK |
|
1872
|
/* |
|
1873
|
** Deallocate and destroy a parser. Destructors are called for |
|
1874
|
** all stack elements before shutting the parser down. |
|
1875
|
** |
|
1876
|
** If the YYPARSEFREENEVERNULL macro exists (for example because it |
|
1877
|
** is defined in a %include section of the input grammar) then it is |
|
1878
|
** assumed that the input pointer is never NULL. |
|
1879
|
*/ |
|
1880
|
void pik_parserFree( |
|
1881
|
void *p, /* The parser to be deleted */ |
|
1882
|
void (*freeProc)(void*) /* Function used to reclaim memory */ |
|
1883
|
){ |
|
1884
|
#ifndef YYPARSEFREENEVERNULL |
|
1885
|
if( p==0 ) return; |
|
1886
|
#endif |
|
1887
|
pik_parserFinalize(p); |
|
1888
|
(*freeProc)(p); |
|
1889
|
} |
|
1890
|
#endif /* pik_parser_ENGINEALWAYSONSTACK */ |
|
1891
|
|
|
1892
|
/* |
|
1893
|
** Return the peak depth of the stack for a parser. |
|
1894
|
*/ |
|
1895
|
#ifdef YYTRACKMAXSTACKDEPTH |
|
1896
|
int pik_parserStackPeak(void *p){ |
|
1897
|
yyParser *pParser = (yyParser*)p; |
|
1898
|
return pParser->yyhwm; |
|
1899
|
} |
|
1900
|
#endif |
|
1901
|
|
|
1902
|
/* This array of booleans keeps track of the parser statement |
|
1903
|
** coverage. The element yycoverage[X][Y] is set when the parser |
|
1904
|
** is in state X and has a lookahead token Y. In a well-tested |
|
1905
|
** systems, every element of this matrix should end up being set. |
|
1906
|
*/ |
|
1907
|
#if defined(YYCOVERAGE) |
|
1908
|
static unsigned char yycoverage[YYNSTATE][YYNTOKEN]; |
|
1909
|
#endif |
|
1910
|
|
|
1911
|
/* |
|
1912
|
** Write into out a description of every state/lookahead combination that |
|
1913
|
** |
|
1914
|
** (1) has not been used by the parser, and |
|
1915
|
** (2) is not a syntax error. |
|
1916
|
** |
|
1917
|
** Return the number of missed state/lookahead combinations. |
|
1918
|
*/ |
|
1919
|
#if defined(YYCOVERAGE) |
|
1920
|
int pik_parserCoverage(FILE *out){ |
|
1921
|
int stateno, iLookAhead, i; |
|
1922
|
int nMissed = 0; |
|
1923
|
for(stateno=0; stateno<YYNSTATE; stateno++){ |
|
1924
|
i = yy_shift_ofst[stateno]; |
|
1925
|
for(iLookAhead=0; iLookAhead<YYNTOKEN; iLookAhead++){ |
|
1926
|
if( yy_lookahead[i+iLookAhead]!=iLookAhead ) continue; |
|
1927
|
if( yycoverage[stateno][iLookAhead]==0 ) nMissed++; |
|
1928
|
if( out ){ |
|
1929
|
fprintf(out,"State %d lookahead %s %s\n", stateno, |
|
1930
|
yyTokenName[iLookAhead], |
|
1931
|
yycoverage[stateno][iLookAhead] ? "ok" : "missed"); |
|
1932
|
} |
|
1933
|
} |
|
1934
|
} |
|
1935
|
return nMissed; |
|
1936
|
} |
|
1937
|
#endif |
|
1938
|
|
|
1939
|
/* |
|
1940
|
** Find the appropriate action for a parser given the terminal |
|
1941
|
** look-ahead token iLookAhead. |
|
1942
|
*/ |
|
1943
|
static YYACTIONTYPE yy_find_shift_action( |
|
1944
|
YYCODETYPE iLookAhead, /* The look-ahead token */ |
|
1945
|
YYACTIONTYPE stateno /* Current state number */ |
|
1946
|
){ |
|
1947
|
int i; |
|
1948
|
|
|
1949
|
if( stateno>YY_MAX_SHIFT ) return stateno; |
|
1950
|
assert( stateno <= YY_SHIFT_COUNT ); |
|
1951
|
#if defined(YYCOVERAGE) |
|
1952
|
yycoverage[stateno][iLookAhead] = 1; |
|
1953
|
#endif |
|
1954
|
do{ |
|
1955
|
i = yy_shift_ofst[stateno]; |
|
1956
|
assert( i>=0 ); |
|
1957
|
assert( i<=YY_ACTTAB_COUNT ); |
|
1958
|
assert( i+YYNTOKEN<=(int)YY_NLOOKAHEAD ); |
|
1959
|
assert( iLookAhead!=YYNOCODE ); |
|
1960
|
assert( iLookAhead < YYNTOKEN ); |
|
1961
|
i += iLookAhead; |
|
1962
|
assert( i<(int)YY_NLOOKAHEAD ); |
|
1963
|
if( yy_lookahead[i]!=iLookAhead ){ |
|
1964
|
#ifdef YYFALLBACK |
|
1965
|
YYCODETYPE iFallback; /* Fallback token */ |
|
1966
|
assert( iLookAhead<sizeof(yyFallback)/sizeof(yyFallback[0]) ); |
|
1967
|
iFallback = yyFallback[iLookAhead]; |
|
1968
|
if( iFallback!=0 ){ |
|
1969
|
#ifndef NDEBUG |
|
1970
|
if( yyTraceFILE ){ |
|
1971
|
fprintf(yyTraceFILE, "%sFALLBACK %s => %s\n", |
|
1972
|
yyTracePrompt, yyTokenName[iLookAhead], yyTokenName[iFallback]); |
|
1973
|
} |
|
1974
|
#endif |
|
1975
|
assert( yyFallback[iFallback]==0 ); /* Fallback loop must terminate */ |
|
1976
|
iLookAhead = iFallback; |
|
1977
|
continue; |
|
1978
|
} |
|
1979
|
#endif |
|
1980
|
#ifdef YYWILDCARD |
|
1981
|
{ |
|
1982
|
int j = i - iLookAhead + YYWILDCARD; |
|
1983
|
assert( j<(int)(sizeof(yy_lookahead)/sizeof(yy_lookahead[0])) ); |
|
1984
|
if( yy_lookahead[j]==YYWILDCARD && iLookAhead>0 ){ |
|
1985
|
#ifndef NDEBUG |
|
1986
|
if( yyTraceFILE ){ |
|
1987
|
fprintf(yyTraceFILE, "%sWILDCARD %s => %s\n", |
|
1988
|
yyTracePrompt, yyTokenName[iLookAhead], |
|
1989
|
yyTokenName[YYWILDCARD]); |
|
1990
|
} |
|
1991
|
#endif /* NDEBUG */ |
|
1992
|
return yy_action[j]; |
|
1993
|
} |
|
1994
|
} |
|
1995
|
#endif /* YYWILDCARD */ |
|
1996
|
return yy_default[stateno]; |
|
1997
|
}else{ |
|
1998
|
assert( i>=0 && i<(int)(sizeof(yy_action)/sizeof(yy_action[0])) ); |
|
1999
|
return yy_action[i]; |
|
2000
|
} |
|
2001
|
}while(1); |
|
2002
|
} |
|
2003
|
|
|
2004
|
/* |
|
2005
|
** Find the appropriate action for a parser given the non-terminal |
|
2006
|
** look-ahead token iLookAhead. |
|
2007
|
*/ |
|
2008
|
static YYACTIONTYPE yy_find_reduce_action( |
|
2009
|
YYACTIONTYPE stateno, /* Current state number */ |
|
2010
|
YYCODETYPE iLookAhead /* The look-ahead token */ |
|
2011
|
){ |
|
2012
|
int i; |
|
2013
|
#ifdef YYERRORSYMBOL |
|
2014
|
if( stateno>YY_REDUCE_COUNT ){ |
|
2015
|
return yy_default[stateno]; |
|
2016
|
} |
|
2017
|
#else |
|
2018
|
assert( stateno<=YY_REDUCE_COUNT ); |
|
2019
|
#endif |
|
2020
|
i = yy_reduce_ofst[stateno]; |
|
2021
|
assert( iLookAhead!=YYNOCODE ); |
|
2022
|
i += iLookAhead; |
|
2023
|
#ifdef YYERRORSYMBOL |
|
2024
|
if( i<0 || i>=YY_ACTTAB_COUNT || yy_lookahead[i]!=iLookAhead ){ |
|
2025
|
return yy_default[stateno]; |
|
2026
|
} |
|
2027
|
#else |
|
2028
|
assert( i>=0 && i<YY_ACTTAB_COUNT ); |
|
2029
|
assert( yy_lookahead[i]==iLookAhead ); |
|
2030
|
#endif |
|
2031
|
return yy_action[i]; |
|
2032
|
} |
|
2033
|
|
|
2034
|
/* |
|
2035
|
** The following routine is called if the stack overflows. |
|
2036
|
*/ |
|
2037
|
static void yyStackOverflow(yyParser *yypParser){ |
|
2038
|
pik_parserARG_FETCH |
|
2039
|
pik_parserCTX_FETCH |
|
2040
|
#ifndef NDEBUG |
|
2041
|
if( yyTraceFILE ){ |
|
2042
|
fprintf(yyTraceFILE,"%sStack Overflow!\n",yyTracePrompt); |
|
2043
|
} |
|
2044
|
#endif |
|
2045
|
while( yypParser->yytos>yypParser->yystack ) yy_pop_parser_stack(yypParser); |
|
2046
|
/* Here code is inserted which will execute if the parser |
|
2047
|
** stack every overflows */ |
|
2048
|
/******** Begin %stack_overflow code ******************************************/ |
|
2049
|
#line 559 "pikchr.y" |
|
2050
|
|
|
2051
|
pik_error(p, 0, "parser stack overflow"); |
|
2052
|
#line 2052 "pikchr.c" |
|
2053
|
/******** End %stack_overflow code ********************************************/ |
|
2054
|
pik_parserARG_STORE /* Suppress warning about unused %extra_argument var */ |
|
2055
|
pik_parserCTX_STORE |
|
2056
|
} |
|
2057
|
|
|
2058
|
/* |
|
2059
|
** Print tracing information for a SHIFT action |
|
2060
|
*/ |
|
2061
|
#ifndef NDEBUG |
|
2062
|
static void yyTraceShift(yyParser *yypParser, int yyNewState, const char *zTag){ |
|
2063
|
if( yyTraceFILE ){ |
|
2064
|
if( yyNewState<YYNSTATE ){ |
|
2065
|
fprintf(yyTraceFILE,"%s%s '%s', go to state %d\n", |
|
2066
|
yyTracePrompt, zTag, yyTokenName[yypParser->yytos->major], |
|
2067
|
yyNewState); |
|
2068
|
}else{ |
|
2069
|
fprintf(yyTraceFILE,"%s%s '%s', pending reduce %d\n", |
|
2070
|
yyTracePrompt, zTag, yyTokenName[yypParser->yytos->major], |
|
2071
|
yyNewState - YY_MIN_REDUCE); |
|
2072
|
} |
|
2073
|
} |
|
2074
|
} |
|
2075
|
#else |
|
2076
|
# define yyTraceShift(X,Y,Z) |
|
2077
|
#endif |
|
2078
|
|
|
2079
|
/* |
|
2080
|
** Perform a shift action. |
|
2081
|
*/ |
|
2082
|
static void yy_shift( |
|
2083
|
yyParser *yypParser, /* The parser to be shifted */ |
|
2084
|
YYACTIONTYPE yyNewState, /* The new state to shift in */ |
|
2085
|
YYCODETYPE yyMajor, /* The major token to shift in */ |
|
2086
|
pik_parserTOKENTYPE yyMinor /* The minor token to shift in */ |
|
2087
|
){ |
|
2088
|
yyStackEntry *yytos; |
|
2089
|
yypParser->yytos++; |
|
2090
|
#ifdef YYTRACKMAXSTACKDEPTH |
|
2091
|
if( (int)(yypParser->yytos - yypParser->yystack)>yypParser->yyhwm ){ |
|
2092
|
yypParser->yyhwm++; |
|
2093
|
assert( yypParser->yyhwm == (int)(yypParser->yytos - yypParser->yystack) ); |
|
2094
|
} |
|
2095
|
#endif |
|
2096
|
yytos = yypParser->yytos; |
|
2097
|
if( yytos>yypParser->yystackEnd ){ |
|
2098
|
if( yyGrowStack(yypParser) ){ |
|
2099
|
yypParser->yytos--; |
|
2100
|
yyStackOverflow(yypParser); |
|
2101
|
return; |
|
2102
|
} |
|
2103
|
yytos = yypParser->yytos; |
|
2104
|
assert( yytos <= yypParser->yystackEnd ); |
|
2105
|
} |
|
2106
|
if( yyNewState > YY_MAX_SHIFT ){ |
|
2107
|
yyNewState += YY_MIN_REDUCE - YY_MIN_SHIFTREDUCE; |
|
2108
|
} |
|
2109
|
yytos->stateno = yyNewState; |
|
2110
|
yytos->major = yyMajor; |
|
2111
|
yytos->minor.yy0 = yyMinor; |
|
2112
|
yyTraceShift(yypParser, yyNewState, "Shift"); |
|
2113
|
} |
|
2114
|
|
|
2115
|
/* For rule J, yyRuleInfoLhs[J] contains the symbol on the left-hand side |
|
2116
|
** of that rule */ |
|
2117
|
static const YYCODETYPE yyRuleInfoLhs[] = { |
|
2118
|
124, /* (0) document ::= statement_list */ |
|
2119
|
101, /* (1) statement_list ::= statement */ |
|
2120
|
101, /* (2) statement_list ::= statement_list EOL statement */ |
|
2121
|
102, /* (3) statement ::= */ |
|
2122
|
102, /* (4) statement ::= direction */ |
|
2123
|
102, /* (5) statement ::= lvalue ASSIGN rvalue */ |
|
2124
|
102, /* (6) statement ::= PLACENAME COLON unnamed_statement */ |
|
2125
|
102, /* (7) statement ::= PLACENAME COLON position */ |
|
2126
|
102, /* (8) statement ::= unnamed_statement */ |
|
2127
|
102, /* (9) statement ::= print prlist */ |
|
2128
|
102, /* (10) statement ::= ASSERT LP expr EQ expr RP */ |
|
2129
|
102, /* (11) statement ::= ASSERT LP position EQ position RP */ |
|
2130
|
102, /* (12) statement ::= DEFINE ID CODEBLOCK */ |
|
2131
|
119, /* (13) rvalue ::= PLACENAME */ |
|
2132
|
127, /* (14) pritem ::= FILL */ |
|
2133
|
127, /* (15) pritem ::= COLOR */ |
|
2134
|
127, /* (16) pritem ::= THICKNESS */ |
|
2135
|
127, /* (17) pritem ::= rvalue */ |
|
2136
|
127, /* (18) pritem ::= STRING */ |
|
2137
|
128, /* (19) prsep ::= COMMA */ |
|
2138
|
103, /* (20) unnamed_statement ::= basetype attribute_list */ |
|
2139
|
104, /* (21) basetype ::= CLASSNAME */ |
|
2140
|
104, /* (22) basetype ::= STRING textposition */ |
|
2141
|
104, /* (23) basetype ::= LB savelist statement_list RB */ |
|
2142
|
130, /* (24) savelist ::= */ |
|
2143
|
122, /* (25) relexpr ::= expr */ |
|
2144
|
122, /* (26) relexpr ::= expr PERCENT */ |
|
2145
|
123, /* (27) optrelexpr ::= */ |
|
2146
|
129, /* (28) attribute_list ::= relexpr alist */ |
|
2147
|
132, /* (29) attribute ::= numproperty relexpr */ |
|
2148
|
132, /* (30) attribute ::= dashproperty expr */ |
|
2149
|
132, /* (31) attribute ::= dashproperty */ |
|
2150
|
132, /* (32) attribute ::= colorproperty rvalue */ |
|
2151
|
132, /* (33) attribute ::= go direction optrelexpr */ |
|
2152
|
132, /* (34) attribute ::= go direction even position */ |
|
2153
|
132, /* (35) attribute ::= CLOSE */ |
|
2154
|
132, /* (36) attribute ::= CHOP */ |
|
2155
|
132, /* (37) attribute ::= FROM position */ |
|
2156
|
132, /* (38) attribute ::= TO position */ |
|
2157
|
132, /* (39) attribute ::= THEN */ |
|
2158
|
132, /* (40) attribute ::= THEN optrelexpr HEADING expr */ |
|
2159
|
132, /* (41) attribute ::= THEN optrelexpr EDGEPT */ |
|
2160
|
132, /* (42) attribute ::= GO optrelexpr HEADING expr */ |
|
2161
|
132, /* (43) attribute ::= GO optrelexpr EDGEPT */ |
|
2162
|
132, /* (44) attribute ::= AT position */ |
|
2163
|
132, /* (45) attribute ::= SAME */ |
|
2164
|
132, /* (46) attribute ::= SAME AS object */ |
|
2165
|
132, /* (47) attribute ::= STRING textposition */ |
|
2166
|
132, /* (48) attribute ::= FIT */ |
|
2167
|
132, /* (49) attribute ::= BEHIND object */ |
|
2168
|
135, /* (50) withclause ::= DOT_E edge AT position */ |
|
2169
|
135, /* (51) withclause ::= edge AT position */ |
|
2170
|
106, /* (52) numproperty ::= HEIGHT|WIDTH|RADIUS|DIAMETER|THICKNESS */ |
|
2171
|
134, /* (53) boolproperty ::= CW */ |
|
2172
|
134, /* (54) boolproperty ::= CCW */ |
|
2173
|
134, /* (55) boolproperty ::= LARROW */ |
|
2174
|
134, /* (56) boolproperty ::= RARROW */ |
|
2175
|
134, /* (57) boolproperty ::= LRARROW */ |
|
2176
|
134, /* (58) boolproperty ::= INVIS */ |
|
2177
|
134, /* (59) boolproperty ::= THICK */ |
|
2178
|
134, /* (60) boolproperty ::= THIN */ |
|
2179
|
134, /* (61) boolproperty ::= SOLID */ |
|
2180
|
118, /* (62) textposition ::= */ |
|
2181
|
118, /* (63) textposition ::= textposition CENTER|LJUST|RJUST|ABOVE|BELOW|ITALIC|BOLD|MONO|ALIGNED|BIG|SMALL */ |
|
2182
|
113, /* (64) position ::= expr COMMA expr */ |
|
2183
|
113, /* (65) position ::= place PLUS expr COMMA expr */ |
|
2184
|
113, /* (66) position ::= place MINUS expr COMMA expr */ |
|
2185
|
113, /* (67) position ::= place PLUS LP expr COMMA expr RP */ |
|
2186
|
113, /* (68) position ::= place MINUS LP expr COMMA expr RP */ |
|
2187
|
113, /* (69) position ::= LP position COMMA position RP */ |
|
2188
|
113, /* (70) position ::= LP position RP */ |
|
2189
|
113, /* (71) position ::= expr between position AND position */ |
|
2190
|
113, /* (72) position ::= expr LT position COMMA position GT */ |
|
2191
|
113, /* (73) position ::= expr ABOVE position */ |
|
2192
|
113, /* (74) position ::= expr BELOW position */ |
|
2193
|
113, /* (75) position ::= expr LEFT OF position */ |
|
2194
|
113, /* (76) position ::= expr RIGHT OF position */ |
|
2195
|
113, /* (77) position ::= expr ON HEADING EDGEPT OF position */ |
|
2196
|
113, /* (78) position ::= expr HEADING EDGEPT OF position */ |
|
2197
|
113, /* (79) position ::= expr EDGEPT OF position */ |
|
2198
|
113, /* (80) position ::= expr ON HEADING expr FROM position */ |
|
2199
|
113, /* (81) position ::= expr HEADING expr FROM position */ |
|
2200
|
114, /* (82) place ::= edge OF object */ |
|
2201
|
137, /* (83) place2 ::= object */ |
|
2202
|
137, /* (84) place2 ::= object DOT_E edge */ |
|
2203
|
137, /* (85) place2 ::= NTH VERTEX OF object */ |
|
2204
|
115, /* (86) object ::= nth */ |
|
2205
|
115, /* (87) object ::= nth OF|IN object */ |
|
2206
|
116, /* (88) objectname ::= THIS */ |
|
2207
|
116, /* (89) objectname ::= PLACENAME */ |
|
2208
|
116, /* (90) objectname ::= objectname DOT_U PLACENAME */ |
|
2209
|
117, /* (91) nth ::= NTH CLASSNAME */ |
|
2210
|
117, /* (92) nth ::= NTH LAST CLASSNAME */ |
|
2211
|
117, /* (93) nth ::= LAST CLASSNAME */ |
|
2212
|
117, /* (94) nth ::= LAST */ |
|
2213
|
117, /* (95) nth ::= NTH LB RB */ |
|
2214
|
117, /* (96) nth ::= NTH LAST LB RB */ |
|
2215
|
117, /* (97) nth ::= LAST LB RB */ |
|
2216
|
105, /* (98) expr ::= expr PLUS expr */ |
|
2217
|
105, /* (99) expr ::= expr MINUS expr */ |
|
2218
|
105, /* (100) expr ::= expr STAR expr */ |
|
2219
|
105, /* (101) expr ::= expr SLASH expr */ |
|
2220
|
105, /* (102) expr ::= MINUS expr */ |
|
2221
|
105, /* (103) expr ::= PLUS expr */ |
|
2222
|
105, /* (104) expr ::= LP expr RP */ |
|
2223
|
105, /* (105) expr ::= LP FILL|COLOR|THICKNESS RP */ |
|
2224
|
105, /* (106) expr ::= NUMBER */ |
|
2225
|
105, /* (107) expr ::= ID */ |
|
2226
|
105, /* (108) expr ::= FUNC1 LP expr RP */ |
|
2227
|
105, /* (109) expr ::= FUNC2 LP expr COMMA expr RP */ |
|
2228
|
105, /* (110) expr ::= DIST LP position COMMA position RP */ |
|
2229
|
105, /* (111) expr ::= place2 DOT_XY X */ |
|
2230
|
105, /* (112) expr ::= place2 DOT_XY Y */ |
|
2231
|
105, /* (113) expr ::= object DOT_L numproperty */ |
|
2232
|
105, /* (114) expr ::= object DOT_L dashproperty */ |
|
2233
|
105, /* (115) expr ::= object DOT_L colorproperty */ |
|
2234
|
120, /* (116) lvalue ::= ID */ |
|
2235
|
120, /* (117) lvalue ::= FILL */ |
|
2236
|
120, /* (118) lvalue ::= COLOR */ |
|
2237
|
120, /* (119) lvalue ::= THICKNESS */ |
|
2238
|
119, /* (120) rvalue ::= expr */ |
|
2239
|
125, /* (121) print ::= PRINT */ |
|
2240
|
126, /* (122) prlist ::= pritem */ |
|
2241
|
126, /* (123) prlist ::= prlist prsep pritem */ |
|
2242
|
109, /* (124) direction ::= UP */ |
|
2243
|
109, /* (125) direction ::= DOWN */ |
|
2244
|
109, /* (126) direction ::= LEFT */ |
|
2245
|
109, /* (127) direction ::= RIGHT */ |
|
2246
|
123, /* (128) optrelexpr ::= relexpr */ |
|
2247
|
129, /* (129) attribute_list ::= alist */ |
|
2248
|
131, /* (130) alist ::= */ |
|
2249
|
131, /* (131) alist ::= alist attribute */ |
|
2250
|
132, /* (132) attribute ::= boolproperty */ |
|
2251
|
132, /* (133) attribute ::= WITH withclause */ |
|
2252
|
133, /* (134) go ::= GO */ |
|
2253
|
133, /* (135) go ::= */ |
|
2254
|
121, /* (136) even ::= UNTIL EVEN WITH */ |
|
2255
|
121, /* (137) even ::= EVEN WITH */ |
|
2256
|
110, /* (138) dashproperty ::= DOTTED */ |
|
2257
|
110, /* (139) dashproperty ::= DASHED */ |
|
2258
|
111, /* (140) colorproperty ::= FILL */ |
|
2259
|
111, /* (141) colorproperty ::= COLOR */ |
|
2260
|
113, /* (142) position ::= place */ |
|
2261
|
136, /* (143) between ::= WAY BETWEEN */ |
|
2262
|
136, /* (144) between ::= BETWEEN */ |
|
2263
|
136, /* (145) between ::= OF THE WAY BETWEEN */ |
|
2264
|
114, /* (146) place ::= place2 */ |
|
2265
|
107, /* (147) edge ::= CENTER */ |
|
2266
|
107, /* (148) edge ::= EDGEPT */ |
|
2267
|
107, /* (149) edge ::= TOP */ |
|
2268
|
107, /* (150) edge ::= BOTTOM */ |
|
2269
|
107, /* (151) edge ::= START */ |
|
2270
|
107, /* (152) edge ::= END */ |
|
2271
|
107, /* (153) edge ::= RIGHT */ |
|
2272
|
107, /* (154) edge ::= LEFT */ |
|
2273
|
115, /* (155) object ::= objectname */ |
|
2274
|
}; |
|
2275
|
|
|
2276
|
/* For rule J, yyRuleInfoNRhs[J] contains the negative of the number |
|
2277
|
** of symbols on the right-hand side of that rule. */ |
|
2278
|
static const signed char yyRuleInfoNRhs[] = { |
|
2279
|
-1, /* (0) document ::= statement_list */ |
|
2280
|
-1, /* (1) statement_list ::= statement */ |
|
2281
|
-3, /* (2) statement_list ::= statement_list EOL statement */ |
|
2282
|
0, /* (3) statement ::= */ |
|
2283
|
-1, /* (4) statement ::= direction */ |
|
2284
|
-3, /* (5) statement ::= lvalue ASSIGN rvalue */ |
|
2285
|
-3, /* (6) statement ::= PLACENAME COLON unnamed_statement */ |
|
2286
|
-3, /* (7) statement ::= PLACENAME COLON position */ |
|
2287
|
-1, /* (8) statement ::= unnamed_statement */ |
|
2288
|
-2, /* (9) statement ::= print prlist */ |
|
2289
|
-6, /* (10) statement ::= ASSERT LP expr EQ expr RP */ |
|
2290
|
-6, /* (11) statement ::= ASSERT LP position EQ position RP */ |
|
2291
|
-3, /* (12) statement ::= DEFINE ID CODEBLOCK */ |
|
2292
|
-1, /* (13) rvalue ::= PLACENAME */ |
|
2293
|
-1, /* (14) pritem ::= FILL */ |
|
2294
|
-1, /* (15) pritem ::= COLOR */ |
|
2295
|
-1, /* (16) pritem ::= THICKNESS */ |
|
2296
|
-1, /* (17) pritem ::= rvalue */ |
|
2297
|
-1, /* (18) pritem ::= STRING */ |
|
2298
|
-1, /* (19) prsep ::= COMMA */ |
|
2299
|
-2, /* (20) unnamed_statement ::= basetype attribute_list */ |
|
2300
|
-1, /* (21) basetype ::= CLASSNAME */ |
|
2301
|
-2, /* (22) basetype ::= STRING textposition */ |
|
2302
|
-4, /* (23) basetype ::= LB savelist statement_list RB */ |
|
2303
|
0, /* (24) savelist ::= */ |
|
2304
|
-1, /* (25) relexpr ::= expr */ |
|
2305
|
-2, /* (26) relexpr ::= expr PERCENT */ |
|
2306
|
0, /* (27) optrelexpr ::= */ |
|
2307
|
-2, /* (28) attribute_list ::= relexpr alist */ |
|
2308
|
-2, /* (29) attribute ::= numproperty relexpr */ |
|
2309
|
-2, /* (30) attribute ::= dashproperty expr */ |
|
2310
|
-1, /* (31) attribute ::= dashproperty */ |
|
2311
|
-2, /* (32) attribute ::= colorproperty rvalue */ |
|
2312
|
-3, /* (33) attribute ::= go direction optrelexpr */ |
|
2313
|
-4, /* (34) attribute ::= go direction even position */ |
|
2314
|
-1, /* (35) attribute ::= CLOSE */ |
|
2315
|
-1, /* (36) attribute ::= CHOP */ |
|
2316
|
-2, /* (37) attribute ::= FROM position */ |
|
2317
|
-2, /* (38) attribute ::= TO position */ |
|
2318
|
-1, /* (39) attribute ::= THEN */ |
|
2319
|
-4, /* (40) attribute ::= THEN optrelexpr HEADING expr */ |
|
2320
|
-3, /* (41) attribute ::= THEN optrelexpr EDGEPT */ |
|
2321
|
-4, /* (42) attribute ::= GO optrelexpr HEADING expr */ |
|
2322
|
-3, /* (43) attribute ::= GO optrelexpr EDGEPT */ |
|
2323
|
-2, /* (44) attribute ::= AT position */ |
|
2324
|
-1, /* (45) attribute ::= SAME */ |
|
2325
|
-3, /* (46) attribute ::= SAME AS object */ |
|
2326
|
-2, /* (47) attribute ::= STRING textposition */ |
|
2327
|
-1, /* (48) attribute ::= FIT */ |
|
2328
|
-2, /* (49) attribute ::= BEHIND object */ |
|
2329
|
-4, /* (50) withclause ::= DOT_E edge AT position */ |
|
2330
|
-3, /* (51) withclause ::= edge AT position */ |
|
2331
|
-1, /* (52) numproperty ::= HEIGHT|WIDTH|RADIUS|DIAMETER|THICKNESS */ |
|
2332
|
-1, /* (53) boolproperty ::= CW */ |
|
2333
|
-1, /* (54) boolproperty ::= CCW */ |
|
2334
|
-1, /* (55) boolproperty ::= LARROW */ |
|
2335
|
-1, /* (56) boolproperty ::= RARROW */ |
|
2336
|
-1, /* (57) boolproperty ::= LRARROW */ |
|
2337
|
-1, /* (58) boolproperty ::= INVIS */ |
|
2338
|
-1, /* (59) boolproperty ::= THICK */ |
|
2339
|
-1, /* (60) boolproperty ::= THIN */ |
|
2340
|
-1, /* (61) boolproperty ::= SOLID */ |
|
2341
|
0, /* (62) textposition ::= */ |
|
2342
|
-2, /* (63) textposition ::= textposition CENTER|LJUST|RJUST|ABOVE|BELOW|ITALIC|BOLD|MONO|ALIGNED|BIG|SMALL */ |
|
2343
|
-3, /* (64) position ::= expr COMMA expr */ |
|
2344
|
-5, /* (65) position ::= place PLUS expr COMMA expr */ |
|
2345
|
-5, /* (66) position ::= place MINUS expr COMMA expr */ |
|
2346
|
-7, /* (67) position ::= place PLUS LP expr COMMA expr RP */ |
|
2347
|
-7, /* (68) position ::= place MINUS LP expr COMMA expr RP */ |
|
2348
|
-5, /* (69) position ::= LP position COMMA position RP */ |
|
2349
|
-3, /* (70) position ::= LP position RP */ |
|
2350
|
-5, /* (71) position ::= expr between position AND position */ |
|
2351
|
-6, /* (72) position ::= expr LT position COMMA position GT */ |
|
2352
|
-3, /* (73) position ::= expr ABOVE position */ |
|
2353
|
-3, /* (74) position ::= expr BELOW position */ |
|
2354
|
-4, /* (75) position ::= expr LEFT OF position */ |
|
2355
|
-4, /* (76) position ::= expr RIGHT OF position */ |
|
2356
|
-6, /* (77) position ::= expr ON HEADING EDGEPT OF position */ |
|
2357
|
-5, /* (78) position ::= expr HEADING EDGEPT OF position */ |
|
2358
|
-4, /* (79) position ::= expr EDGEPT OF position */ |
|
2359
|
-6, /* (80) position ::= expr ON HEADING expr FROM position */ |
|
2360
|
-5, /* (81) position ::= expr HEADING expr FROM position */ |
|
2361
|
-3, /* (82) place ::= edge OF object */ |
|
2362
|
-1, /* (83) place2 ::= object */ |
|
2363
|
-3, /* (84) place2 ::= object DOT_E edge */ |
|
2364
|
-4, /* (85) place2 ::= NTH VERTEX OF object */ |
|
2365
|
-1, /* (86) object ::= nth */ |
|
2366
|
-3, /* (87) object ::= nth OF|IN object */ |
|
2367
|
-1, /* (88) objectname ::= THIS */ |
|
2368
|
-1, /* (89) objectname ::= PLACENAME */ |
|
2369
|
-3, /* (90) objectname ::= objectname DOT_U PLACENAME */ |
|
2370
|
-2, /* (91) nth ::= NTH CLASSNAME */ |
|
2371
|
-3, /* (92) nth ::= NTH LAST CLASSNAME */ |
|
2372
|
-2, /* (93) nth ::= LAST CLASSNAME */ |
|
2373
|
-1, /* (94) nth ::= LAST */ |
|
2374
|
-3, /* (95) nth ::= NTH LB RB */ |
|
2375
|
-4, /* (96) nth ::= NTH LAST LB RB */ |
|
2376
|
-3, /* (97) nth ::= LAST LB RB */ |
|
2377
|
-3, /* (98) expr ::= expr PLUS expr */ |
|
2378
|
-3, /* (99) expr ::= expr MINUS expr */ |
|
2379
|
-3, /* (100) expr ::= expr STAR expr */ |
|
2380
|
-3, /* (101) expr ::= expr SLASH expr */ |
|
2381
|
-2, /* (102) expr ::= MINUS expr */ |
|
2382
|
-2, /* (103) expr ::= PLUS expr */ |
|
2383
|
-3, /* (104) expr ::= LP expr RP */ |
|
2384
|
-3, /* (105) expr ::= LP FILL|COLOR|THICKNESS RP */ |
|
2385
|
-1, /* (106) expr ::= NUMBER */ |
|
2386
|
-1, /* (107) expr ::= ID */ |
|
2387
|
-4, /* (108) expr ::= FUNC1 LP expr RP */ |
|
2388
|
-6, /* (109) expr ::= FUNC2 LP expr COMMA expr RP */ |
|
2389
|
-6, /* (110) expr ::= DIST LP position COMMA position RP */ |
|
2390
|
-3, /* (111) expr ::= place2 DOT_XY X */ |
|
2391
|
-3, /* (112) expr ::= place2 DOT_XY Y */ |
|
2392
|
-3, /* (113) expr ::= object DOT_L numproperty */ |
|
2393
|
-3, /* (114) expr ::= object DOT_L dashproperty */ |
|
2394
|
-3, /* (115) expr ::= object DOT_L colorproperty */ |
|
2395
|
-1, /* (116) lvalue ::= ID */ |
|
2396
|
-1, /* (117) lvalue ::= FILL */ |
|
2397
|
-1, /* (118) lvalue ::= COLOR */ |
|
2398
|
-1, /* (119) lvalue ::= THICKNESS */ |
|
2399
|
-1, /* (120) rvalue ::= expr */ |
|
2400
|
-1, /* (121) print ::= PRINT */ |
|
2401
|
-1, /* (122) prlist ::= pritem */ |
|
2402
|
-3, /* (123) prlist ::= prlist prsep pritem */ |
|
2403
|
-1, /* (124) direction ::= UP */ |
|
2404
|
-1, /* (125) direction ::= DOWN */ |
|
2405
|
-1, /* (126) direction ::= LEFT */ |
|
2406
|
-1, /* (127) direction ::= RIGHT */ |
|
2407
|
-1, /* (128) optrelexpr ::= relexpr */ |
|
2408
|
-1, /* (129) attribute_list ::= alist */ |
|
2409
|
0, /* (130) alist ::= */ |
|
2410
|
-2, /* (131) alist ::= alist attribute */ |
|
2411
|
-1, /* (132) attribute ::= boolproperty */ |
|
2412
|
-2, /* (133) attribute ::= WITH withclause */ |
|
2413
|
-1, /* (134) go ::= GO */ |
|
2414
|
0, /* (135) go ::= */ |
|
2415
|
-3, /* (136) even ::= UNTIL EVEN WITH */ |
|
2416
|
-2, /* (137) even ::= EVEN WITH */ |
|
2417
|
-1, /* (138) dashproperty ::= DOTTED */ |
|
2418
|
-1, /* (139) dashproperty ::= DASHED */ |
|
2419
|
-1, /* (140) colorproperty ::= FILL */ |
|
2420
|
-1, /* (141) colorproperty ::= COLOR */ |
|
2421
|
-1, /* (142) position ::= place */ |
|
2422
|
-2, /* (143) between ::= WAY BETWEEN */ |
|
2423
|
-1, /* (144) between ::= BETWEEN */ |
|
2424
|
-4, /* (145) between ::= OF THE WAY BETWEEN */ |
|
2425
|
-1, /* (146) place ::= place2 */ |
|
2426
|
-1, /* (147) edge ::= CENTER */ |
|
2427
|
-1, /* (148) edge ::= EDGEPT */ |
|
2428
|
-1, /* (149) edge ::= TOP */ |
|
2429
|
-1, /* (150) edge ::= BOTTOM */ |
|
2430
|
-1, /* (151) edge ::= START */ |
|
2431
|
-1, /* (152) edge ::= END */ |
|
2432
|
-1, /* (153) edge ::= RIGHT */ |
|
2433
|
-1, /* (154) edge ::= LEFT */ |
|
2434
|
-1, /* (155) object ::= objectname */ |
|
2435
|
}; |
|
2436
|
|
|
2437
|
static void yy_accept(yyParser*); /* Forward Declaration */ |
|
2438
|
|
|
2439
|
/* |
|
2440
|
** Perform a reduce action and the shift that must immediately |
|
2441
|
** follow the reduce. |
|
2442
|
** |
|
2443
|
** The yyLookahead and yyLookaheadToken parameters provide reduce actions |
|
2444
|
** access to the lookahead token (if any). The yyLookahead will be YYNOCODE |
|
2445
|
** if the lookahead token has already been consumed. As this procedure is |
|
2446
|
** only called from one place, optimizing compilers will in-line it, which |
|
2447
|
** means that the extra parameters have no performance impact. |
|
2448
|
*/ |
|
2449
|
static YYACTIONTYPE yy_reduce( |
|
2450
|
yyParser *yypParser, /* The parser */ |
|
2451
|
unsigned int yyruleno, /* Number of the rule by which to reduce */ |
|
2452
|
int yyLookahead, /* Lookahead token, or YYNOCODE if none */ |
|
2453
|
pik_parserTOKENTYPE yyLookaheadToken /* Value of the lookahead token */ |
|
2454
|
pik_parserCTX_PDECL /* %extra_context */ |
|
2455
|
){ |
|
2456
|
int yygoto; /* The next state */ |
|
2457
|
YYACTIONTYPE yyact; /* The next action */ |
|
2458
|
yyStackEntry *yymsp; /* The top of the parser's stack */ |
|
2459
|
int yysize; /* Amount to pop the stack */ |
|
2460
|
pik_parserARG_FETCH |
|
2461
|
(void)yyLookahead; |
|
2462
|
(void)yyLookaheadToken; |
|
2463
|
yymsp = yypParser->yytos; |
|
2464
|
|
|
2465
|
switch( yyruleno ){ |
|
2466
|
/* Beginning here are the reduction cases. A typical example |
|
2467
|
** follows: |
|
2468
|
** case 0: |
|
2469
|
** #line <lineno> <grammarfile> |
|
2470
|
** { ... } // User supplied code |
|
2471
|
** #line <lineno> <thisfile> |
|
2472
|
** break; |
|
2473
|
*/ |
|
2474
|
/********** Begin reduce actions **********************************************/ |
|
2475
|
YYMINORTYPE yylhsminor; |
|
2476
|
case 0: /* document ::= statement_list */ |
|
2477
|
#line 563 "pikchr.y" |
|
2478
|
{pik_render(p,yymsp[0].minor.yy23);} |
|
2479
|
#line 2479 "pikchr.c" |
|
2480
|
break; |
|
2481
|
case 1: /* statement_list ::= statement */ |
|
2482
|
#line 566 "pikchr.y" |
|
2483
|
{ yylhsminor.yy23 = pik_elist_append(p,0,yymsp[0].minor.yy54); } |
|
2484
|
#line 2484 "pikchr.c" |
|
2485
|
yymsp[0].minor.yy23 = yylhsminor.yy23; |
|
2486
|
break; |
|
2487
|
case 2: /* statement_list ::= statement_list EOL statement */ |
|
2488
|
#line 568 "pikchr.y" |
|
2489
|
{ yylhsminor.yy23 = pik_elist_append(p,yymsp[-2].minor.yy23,yymsp[0].minor.yy54); } |
|
2490
|
#line 2490 "pikchr.c" |
|
2491
|
yymsp[-2].minor.yy23 = yylhsminor.yy23; |
|
2492
|
break; |
|
2493
|
case 3: /* statement ::= */ |
|
2494
|
#line 571 "pikchr.y" |
|
2495
|
{ yymsp[1].minor.yy54 = 0; } |
|
2496
|
#line 2496 "pikchr.c" |
|
2497
|
break; |
|
2498
|
case 4: /* statement ::= direction */ |
|
2499
|
#line 572 "pikchr.y" |
|
2500
|
{ pik_set_direction(p,yymsp[0].minor.yy0.eCode); yylhsminor.yy54=0; } |
|
2501
|
#line 2501 "pikchr.c" |
|
2502
|
yymsp[0].minor.yy54 = yylhsminor.yy54; |
|
2503
|
break; |
|
2504
|
case 5: /* statement ::= lvalue ASSIGN rvalue */ |
|
2505
|
#line 573 "pikchr.y" |
|
2506
|
{pik_set_var(p,&yymsp[-2].minor.yy0,yymsp[0].minor.yy129,&yymsp[-1].minor.yy0); yylhsminor.yy54=0;} |
|
2507
|
#line 2507 "pikchr.c" |
|
2508
|
yymsp[-2].minor.yy54 = yylhsminor.yy54; |
|
2509
|
break; |
|
2510
|
case 6: /* statement ::= PLACENAME COLON unnamed_statement */ |
|
2511
|
#line 575 "pikchr.y" |
|
2512
|
{ yylhsminor.yy54 = yymsp[0].minor.yy54; pik_elem_setname(p,yymsp[0].minor.yy54,&yymsp[-2].minor.yy0); } |
|
2513
|
#line 2513 "pikchr.c" |
|
2514
|
yymsp[-2].minor.yy54 = yylhsminor.yy54; |
|
2515
|
break; |
|
2516
|
case 7: /* statement ::= PLACENAME COLON position */ |
|
2517
|
#line 577 "pikchr.y" |
|
2518
|
{ yylhsminor.yy54 = pik_elem_new(p,0,0,0); |
|
2519
|
if(yylhsminor.yy54){ yylhsminor.yy54->ptAt = yymsp[0].minor.yy187; pik_elem_setname(p,yylhsminor.yy54,&yymsp[-2].minor.yy0); }} |
|
2520
|
#line 2520 "pikchr.c" |
|
2521
|
yymsp[-2].minor.yy54 = yylhsminor.yy54; |
|
2522
|
break; |
|
2523
|
case 8: /* statement ::= unnamed_statement */ |
|
2524
|
#line 579 "pikchr.y" |
|
2525
|
{yylhsminor.yy54 = yymsp[0].minor.yy54;} |
|
2526
|
#line 2526 "pikchr.c" |
|
2527
|
yymsp[0].minor.yy54 = yylhsminor.yy54; |
|
2528
|
break; |
|
2529
|
case 9: /* statement ::= print prlist */ |
|
2530
|
#line 580 "pikchr.y" |
|
2531
|
{pik_append(p,"<br>\n",5); yymsp[-1].minor.yy54=0;} |
|
2532
|
#line 2532 "pikchr.c" |
|
2533
|
break; |
|
2534
|
case 10: /* statement ::= ASSERT LP expr EQ expr RP */ |
|
2535
|
#line 585 "pikchr.y" |
|
2536
|
{yymsp[-5].minor.yy54=pik_assert(p,yymsp[-3].minor.yy129,&yymsp[-2].minor.yy0,yymsp[-1].minor.yy129);} |
|
2537
|
#line 2537 "pikchr.c" |
|
2538
|
break; |
|
2539
|
case 11: /* statement ::= ASSERT LP position EQ position RP */ |
|
2540
|
#line 587 "pikchr.y" |
|
2541
|
{yymsp[-5].minor.yy54=pik_position_assert(p,&yymsp[-3].minor.yy187,&yymsp[-2].minor.yy0,&yymsp[-1].minor.yy187);} |
|
2542
|
#line 2542 "pikchr.c" |
|
2543
|
break; |
|
2544
|
case 12: /* statement ::= DEFINE ID CODEBLOCK */ |
|
2545
|
#line 588 "pikchr.y" |
|
2546
|
{yymsp[-2].minor.yy54=0; pik_add_macro(p,&yymsp[-1].minor.yy0,&yymsp[0].minor.yy0);} |
|
2547
|
#line 2547 "pikchr.c" |
|
2548
|
break; |
|
2549
|
case 13: /* rvalue ::= PLACENAME */ |
|
2550
|
#line 599 "pikchr.y" |
|
2551
|
{yylhsminor.yy129 = pik_lookup_color(p,&yymsp[0].minor.yy0);} |
|
2552
|
#line 2552 "pikchr.c" |
|
2553
|
yymsp[0].minor.yy129 = yylhsminor.yy129; |
|
2554
|
break; |
|
2555
|
case 14: /* pritem ::= FILL */ |
|
2556
|
case 15: /* pritem ::= COLOR */ yytestcase(yyruleno==15); |
|
2557
|
case 16: /* pritem ::= THICKNESS */ yytestcase(yyruleno==16); |
|
2558
|
#line 604 "pikchr.y" |
|
2559
|
{pik_append_num(p,"",pik_value(p,yymsp[0].minor.yy0.z,yymsp[0].minor.yy0.n,0));} |
|
2560
|
#line 2560 "pikchr.c" |
|
2561
|
break; |
|
2562
|
case 17: /* pritem ::= rvalue */ |
|
2563
|
#line 607 "pikchr.y" |
|
2564
|
{pik_append_num(p,"",yymsp[0].minor.yy129);} |
|
2565
|
#line 2565 "pikchr.c" |
|
2566
|
break; |
|
2567
|
case 18: /* pritem ::= STRING */ |
|
2568
|
#line 608 "pikchr.y" |
|
2569
|
{pik_append_text(p,yymsp[0].minor.yy0.z+1,yymsp[0].minor.yy0.n-2,0);} |
|
2570
|
#line 2570 "pikchr.c" |
|
2571
|
break; |
|
2572
|
case 19: /* prsep ::= COMMA */ |
|
2573
|
#line 609 "pikchr.y" |
|
2574
|
{pik_append(p, " ", 1);} |
|
2575
|
#line 2575 "pikchr.c" |
|
2576
|
break; |
|
2577
|
case 20: /* unnamed_statement ::= basetype attribute_list */ |
|
2578
|
#line 614 "pikchr.y" |
|
2579
|
{yylhsminor.yy54 = yymsp[-1].minor.yy54; pik_after_adding_attributes(p,yylhsminor.yy54);} |
|
2580
|
#line 2580 "pikchr.c" |
|
2581
|
yymsp[-1].minor.yy54 = yylhsminor.yy54; |
|
2582
|
break; |
|
2583
|
case 21: /* basetype ::= CLASSNAME */ |
|
2584
|
#line 616 "pikchr.y" |
|
2585
|
{yylhsminor.yy54 = pik_elem_new(p,&yymsp[0].minor.yy0,0,0); } |
|
2586
|
#line 2586 "pikchr.c" |
|
2587
|
yymsp[0].minor.yy54 = yylhsminor.yy54; |
|
2588
|
break; |
|
2589
|
case 22: /* basetype ::= STRING textposition */ |
|
2590
|
#line 618 "pikchr.y" |
|
2591
|
{yymsp[-1].minor.yy0.eCode = yymsp[0].minor.yy272; yylhsminor.yy54 = pik_elem_new(p,0,&yymsp[-1].minor.yy0,0); } |
|
2592
|
#line 2592 "pikchr.c" |
|
2593
|
yymsp[-1].minor.yy54 = yylhsminor.yy54; |
|
2594
|
break; |
|
2595
|
case 23: /* basetype ::= LB savelist statement_list RB */ |
|
2596
|
#line 620 "pikchr.y" |
|
2597
|
{ p->list = yymsp[-2].minor.yy23; yymsp[-3].minor.yy54 = pik_elem_new(p,0,0,yymsp[-1].minor.yy23); if(yymsp[-3].minor.yy54) yymsp[-3].minor.yy54->errTok = yymsp[0].minor.yy0; } |
|
2598
|
#line 2598 "pikchr.c" |
|
2599
|
break; |
|
2600
|
case 24: /* savelist ::= */ |
|
2601
|
#line 625 "pikchr.y" |
|
2602
|
{yymsp[1].minor.yy23 = p->list; p->list = 0;} |
|
2603
|
#line 2603 "pikchr.c" |
|
2604
|
break; |
|
2605
|
case 25: /* relexpr ::= expr */ |
|
2606
|
#line 632 "pikchr.y" |
|
2607
|
{yylhsminor.yy28.rAbs = yymsp[0].minor.yy129; yylhsminor.yy28.rRel = 0;} |
|
2608
|
#line 2608 "pikchr.c" |
|
2609
|
yymsp[0].minor.yy28 = yylhsminor.yy28; |
|
2610
|
break; |
|
2611
|
case 26: /* relexpr ::= expr PERCENT */ |
|
2612
|
#line 633 "pikchr.y" |
|
2613
|
{yylhsminor.yy28.rAbs = 0; yylhsminor.yy28.rRel = yymsp[-1].minor.yy129/100;} |
|
2614
|
#line 2614 "pikchr.c" |
|
2615
|
yymsp[-1].minor.yy28 = yylhsminor.yy28; |
|
2616
|
break; |
|
2617
|
case 27: /* optrelexpr ::= */ |
|
2618
|
#line 635 "pikchr.y" |
|
2619
|
{yymsp[1].minor.yy28.rAbs = 0; yymsp[1].minor.yy28.rRel = 1.0;} |
|
2620
|
#line 2620 "pikchr.c" |
|
2621
|
break; |
|
2622
|
case 28: /* attribute_list ::= relexpr alist */ |
|
2623
|
#line 637 "pikchr.y" |
|
2624
|
{pik_add_direction(p,0,&yymsp[-1].minor.yy28);} |
|
2625
|
#line 2625 "pikchr.c" |
|
2626
|
break; |
|
2627
|
case 29: /* attribute ::= numproperty relexpr */ |
|
2628
|
#line 641 "pikchr.y" |
|
2629
|
{ pik_set_numprop(p,&yymsp[-1].minor.yy0,&yymsp[0].minor.yy28); } |
|
2630
|
#line 2630 "pikchr.c" |
|
2631
|
break; |
|
2632
|
case 30: /* attribute ::= dashproperty expr */ |
|
2633
|
#line 642 "pikchr.y" |
|
2634
|
{ pik_set_dashed(p,&yymsp[-1].minor.yy0,&yymsp[0].minor.yy129); } |
|
2635
|
#line 2635 "pikchr.c" |
|
2636
|
break; |
|
2637
|
case 31: /* attribute ::= dashproperty */ |
|
2638
|
#line 643 "pikchr.y" |
|
2639
|
{ pik_set_dashed(p,&yymsp[0].minor.yy0,0); } |
|
2640
|
#line 2640 "pikchr.c" |
|
2641
|
break; |
|
2642
|
case 32: /* attribute ::= colorproperty rvalue */ |
|
2643
|
#line 644 "pikchr.y" |
|
2644
|
{ pik_set_clrprop(p,&yymsp[-1].minor.yy0,yymsp[0].minor.yy129); } |
|
2645
|
#line 2645 "pikchr.c" |
|
2646
|
break; |
|
2647
|
case 33: /* attribute ::= go direction optrelexpr */ |
|
2648
|
#line 645 "pikchr.y" |
|
2649
|
{ pik_add_direction(p,&yymsp[-1].minor.yy0,&yymsp[0].minor.yy28);} |
|
2650
|
#line 2650 "pikchr.c" |
|
2651
|
break; |
|
2652
|
case 34: /* attribute ::= go direction even position */ |
|
2653
|
#line 646 "pikchr.y" |
|
2654
|
{pik_evenwith(p,&yymsp[-2].minor.yy0,&yymsp[0].minor.yy187);} |
|
2655
|
#line 2655 "pikchr.c" |
|
2656
|
break; |
|
2657
|
case 35: /* attribute ::= CLOSE */ |
|
2658
|
#line 647 "pikchr.y" |
|
2659
|
{ pik_close_path(p,&yymsp[0].minor.yy0); } |
|
2660
|
#line 2660 "pikchr.c" |
|
2661
|
break; |
|
2662
|
case 36: /* attribute ::= CHOP */ |
|
2663
|
#line 648 "pikchr.y" |
|
2664
|
{ p->cur->bChop = 1; } |
|
2665
|
#line 2665 "pikchr.c" |
|
2666
|
break; |
|
2667
|
case 37: /* attribute ::= FROM position */ |
|
2668
|
#line 649 "pikchr.y" |
|
2669
|
{ pik_set_from(p,p->cur,&yymsp[-1].minor.yy0,&yymsp[0].minor.yy187); } |
|
2670
|
#line 2670 "pikchr.c" |
|
2671
|
break; |
|
2672
|
case 38: /* attribute ::= TO position */ |
|
2673
|
#line 650 "pikchr.y" |
|
2674
|
{ pik_add_to(p,p->cur,&yymsp[-1].minor.yy0,&yymsp[0].minor.yy187); } |
|
2675
|
#line 2675 "pikchr.c" |
|
2676
|
break; |
|
2677
|
case 39: /* attribute ::= THEN */ |
|
2678
|
#line 651 "pikchr.y" |
|
2679
|
{ pik_then(p, &yymsp[0].minor.yy0, p->cur); } |
|
2680
|
#line 2680 "pikchr.c" |
|
2681
|
break; |
|
2682
|
case 40: /* attribute ::= THEN optrelexpr HEADING expr */ |
|
2683
|
case 42: /* attribute ::= GO optrelexpr HEADING expr */ yytestcase(yyruleno==42); |
|
2684
|
#line 653 "pikchr.y" |
|
2685
|
{pik_move_hdg(p,&yymsp[-2].minor.yy28,&yymsp[-1].minor.yy0,yymsp[0].minor.yy129,0,&yymsp[-3].minor.yy0);} |
|
2686
|
#line 2686 "pikchr.c" |
|
2687
|
break; |
|
2688
|
case 41: /* attribute ::= THEN optrelexpr EDGEPT */ |
|
2689
|
case 43: /* attribute ::= GO optrelexpr EDGEPT */ yytestcase(yyruleno==43); |
|
2690
|
#line 654 "pikchr.y" |
|
2691
|
{pik_move_hdg(p,&yymsp[-1].minor.yy28,0,0,&yymsp[0].minor.yy0,&yymsp[-2].minor.yy0);} |
|
2692
|
#line 2692 "pikchr.c" |
|
2693
|
break; |
|
2694
|
case 44: /* attribute ::= AT position */ |
|
2695
|
#line 659 "pikchr.y" |
|
2696
|
{ pik_set_at(p,0,&yymsp[0].minor.yy187,&yymsp[-1].minor.yy0); } |
|
2697
|
#line 2697 "pikchr.c" |
|
2698
|
break; |
|
2699
|
case 45: /* attribute ::= SAME */ |
|
2700
|
#line 661 "pikchr.y" |
|
2701
|
{pik_same(p,0,&yymsp[0].minor.yy0);} |
|
2702
|
#line 2702 "pikchr.c" |
|
2703
|
break; |
|
2704
|
case 46: /* attribute ::= SAME AS object */ |
|
2705
|
#line 662 "pikchr.y" |
|
2706
|
{pik_same(p,yymsp[0].minor.yy54,&yymsp[-2].minor.yy0);} |
|
2707
|
#line 2707 "pikchr.c" |
|
2708
|
break; |
|
2709
|
case 47: /* attribute ::= STRING textposition */ |
|
2710
|
#line 663 "pikchr.y" |
|
2711
|
{pik_add_txt(p,&yymsp[-1].minor.yy0,yymsp[0].minor.yy272);} |
|
2712
|
#line 2712 "pikchr.c" |
|
2713
|
break; |
|
2714
|
case 48: /* attribute ::= FIT */ |
|
2715
|
#line 664 "pikchr.y" |
|
2716
|
{pik_size_to_fit(p,0,&yymsp[0].minor.yy0,3); } |
|
2717
|
#line 2717 "pikchr.c" |
|
2718
|
break; |
|
2719
|
case 49: /* attribute ::= BEHIND object */ |
|
2720
|
#line 665 "pikchr.y" |
|
2721
|
{pik_behind(p,yymsp[0].minor.yy54);} |
|
2722
|
#line 2722 "pikchr.c" |
|
2723
|
break; |
|
2724
|
case 50: /* withclause ::= DOT_E edge AT position */ |
|
2725
|
case 51: /* withclause ::= edge AT position */ yytestcase(yyruleno==51); |
|
2726
|
#line 673 "pikchr.y" |
|
2727
|
{ pik_set_at(p,&yymsp[-2].minor.yy0,&yymsp[0].minor.yy187,&yymsp[-1].minor.yy0); } |
|
2728
|
#line 2728 "pikchr.c" |
|
2729
|
break; |
|
2730
|
case 52: /* numproperty ::= HEIGHT|WIDTH|RADIUS|DIAMETER|THICKNESS */ |
|
2731
|
#line 677 "pikchr.y" |
|
2732
|
{yylhsminor.yy0 = yymsp[0].minor.yy0;} |
|
2733
|
#line 2733 "pikchr.c" |
|
2734
|
yymsp[0].minor.yy0 = yylhsminor.yy0; |
|
2735
|
break; |
|
2736
|
case 53: /* boolproperty ::= CW */ |
|
2737
|
#line 688 "pikchr.y" |
|
2738
|
{p->cur->cw = 1;} |
|
2739
|
#line 2739 "pikchr.c" |
|
2740
|
break; |
|
2741
|
case 54: /* boolproperty ::= CCW */ |
|
2742
|
#line 689 "pikchr.y" |
|
2743
|
{p->cur->cw = 0;} |
|
2744
|
#line 2744 "pikchr.c" |
|
2745
|
break; |
|
2746
|
case 55: /* boolproperty ::= LARROW */ |
|
2747
|
#line 690 "pikchr.y" |
|
2748
|
{p->cur->larrow=1; p->cur->rarrow=0; } |
|
2749
|
#line 2749 "pikchr.c" |
|
2750
|
break; |
|
2751
|
case 56: /* boolproperty ::= RARROW */ |
|
2752
|
#line 691 "pikchr.y" |
|
2753
|
{p->cur->larrow=0; p->cur->rarrow=1; } |
|
2754
|
#line 2754 "pikchr.c" |
|
2755
|
break; |
|
2756
|
case 57: /* boolproperty ::= LRARROW */ |
|
2757
|
#line 692 "pikchr.y" |
|
2758
|
{p->cur->larrow=1; p->cur->rarrow=1; } |
|
2759
|
#line 2759 "pikchr.c" |
|
2760
|
break; |
|
2761
|
case 58: /* boolproperty ::= INVIS */ |
|
2762
|
#line 693 "pikchr.y" |
|
2763
|
{p->cur->sw = -0.00001;} |
|
2764
|
#line 2764 "pikchr.c" |
|
2765
|
break; |
|
2766
|
case 59: /* boolproperty ::= THICK */ |
|
2767
|
#line 694 "pikchr.y" |
|
2768
|
{p->cur->sw *= 1.5;} |
|
2769
|
#line 2769 "pikchr.c" |
|
2770
|
break; |
|
2771
|
case 60: /* boolproperty ::= THIN */ |
|
2772
|
#line 695 "pikchr.y" |
|
2773
|
{p->cur->sw *= 0.67;} |
|
2774
|
#line 2774 "pikchr.c" |
|
2775
|
break; |
|
2776
|
case 61: /* boolproperty ::= SOLID */ |
|
2777
|
#line 696 "pikchr.y" |
|
2778
|
{p->cur->sw = pik_value(p,"thickness",9,0); |
|
2779
|
p->cur->dotted = p->cur->dashed = 0.0;} |
|
2780
|
#line 2780 "pikchr.c" |
|
2781
|
break; |
|
2782
|
case 62: /* textposition ::= */ |
|
2783
|
#line 699 "pikchr.y" |
|
2784
|
{yymsp[1].minor.yy272 = 0;} |
|
2785
|
#line 2785 "pikchr.c" |
|
2786
|
break; |
|
2787
|
case 63: /* textposition ::= textposition CENTER|LJUST|RJUST|ABOVE|BELOW|ITALIC|BOLD|MONO|ALIGNED|BIG|SMALL */ |
|
2788
|
#line 702 "pikchr.y" |
|
2789
|
{yylhsminor.yy272 = (short int)pik_text_position(yymsp[-1].minor.yy272,&yymsp[0].minor.yy0);} |
|
2790
|
#line 2790 "pikchr.c" |
|
2791
|
yymsp[-1].minor.yy272 = yylhsminor.yy272; |
|
2792
|
break; |
|
2793
|
case 64: /* position ::= expr COMMA expr */ |
|
2794
|
#line 705 "pikchr.y" |
|
2795
|
{yylhsminor.yy187.x=yymsp[-2].minor.yy129; yylhsminor.yy187.y=yymsp[0].minor.yy129;} |
|
2796
|
#line 2796 "pikchr.c" |
|
2797
|
yymsp[-2].minor.yy187 = yylhsminor.yy187; |
|
2798
|
break; |
|
2799
|
case 65: /* position ::= place PLUS expr COMMA expr */ |
|
2800
|
#line 707 "pikchr.y" |
|
2801
|
{yylhsminor.yy187.x=yymsp[-4].minor.yy187.x+yymsp[-2].minor.yy129; yylhsminor.yy187.y=yymsp[-4].minor.yy187.y+yymsp[0].minor.yy129;} |
|
2802
|
#line 2802 "pikchr.c" |
|
2803
|
yymsp[-4].minor.yy187 = yylhsminor.yy187; |
|
2804
|
break; |
|
2805
|
case 66: /* position ::= place MINUS expr COMMA expr */ |
|
2806
|
#line 708 "pikchr.y" |
|
2807
|
{yylhsminor.yy187.x=yymsp[-4].minor.yy187.x-yymsp[-2].minor.yy129; yylhsminor.yy187.y=yymsp[-4].minor.yy187.y-yymsp[0].minor.yy129;} |
|
2808
|
#line 2808 "pikchr.c" |
|
2809
|
yymsp[-4].minor.yy187 = yylhsminor.yy187; |
|
2810
|
break; |
|
2811
|
case 67: /* position ::= place PLUS LP expr COMMA expr RP */ |
|
2812
|
#line 710 "pikchr.y" |
|
2813
|
{yylhsminor.yy187.x=yymsp[-6].minor.yy187.x+yymsp[-3].minor.yy129; yylhsminor.yy187.y=yymsp[-6].minor.yy187.y+yymsp[-1].minor.yy129;} |
|
2814
|
#line 2814 "pikchr.c" |
|
2815
|
yymsp[-6].minor.yy187 = yylhsminor.yy187; |
|
2816
|
break; |
|
2817
|
case 68: /* position ::= place MINUS LP expr COMMA expr RP */ |
|
2818
|
#line 712 "pikchr.y" |
|
2819
|
{yylhsminor.yy187.x=yymsp[-6].minor.yy187.x-yymsp[-3].minor.yy129; yylhsminor.yy187.y=yymsp[-6].minor.yy187.y-yymsp[-1].minor.yy129;} |
|
2820
|
#line 2820 "pikchr.c" |
|
2821
|
yymsp[-6].minor.yy187 = yylhsminor.yy187; |
|
2822
|
break; |
|
2823
|
case 69: /* position ::= LP position COMMA position RP */ |
|
2824
|
#line 713 "pikchr.y" |
|
2825
|
{yymsp[-4].minor.yy187.x=yymsp[-3].minor.yy187.x; yymsp[-4].minor.yy187.y=yymsp[-1].minor.yy187.y;} |
|
2826
|
#line 2826 "pikchr.c" |
|
2827
|
break; |
|
2828
|
case 70: /* position ::= LP position RP */ |
|
2829
|
#line 714 "pikchr.y" |
|
2830
|
{yymsp[-2].minor.yy187=yymsp[-1].minor.yy187;} |
|
2831
|
#line 2831 "pikchr.c" |
|
2832
|
break; |
|
2833
|
case 71: /* position ::= expr between position AND position */ |
|
2834
|
#line 716 "pikchr.y" |
|
2835
|
{yylhsminor.yy187 = pik_position_between(yymsp[-4].minor.yy129,yymsp[-2].minor.yy187,yymsp[0].minor.yy187);} |
|
2836
|
#line 2836 "pikchr.c" |
|
2837
|
yymsp[-4].minor.yy187 = yylhsminor.yy187; |
|
2838
|
break; |
|
2839
|
case 72: /* position ::= expr LT position COMMA position GT */ |
|
2840
|
#line 718 "pikchr.y" |
|
2841
|
{yylhsminor.yy187 = pik_position_between(yymsp[-5].minor.yy129,yymsp[-3].minor.yy187,yymsp[-1].minor.yy187);} |
|
2842
|
#line 2842 "pikchr.c" |
|
2843
|
yymsp[-5].minor.yy187 = yylhsminor.yy187; |
|
2844
|
break; |
|
2845
|
case 73: /* position ::= expr ABOVE position */ |
|
2846
|
#line 719 "pikchr.y" |
|
2847
|
{yylhsminor.yy187=yymsp[0].minor.yy187; yylhsminor.yy187.y += yymsp[-2].minor.yy129;} |
|
2848
|
#line 2848 "pikchr.c" |
|
2849
|
yymsp[-2].minor.yy187 = yylhsminor.yy187; |
|
2850
|
break; |
|
2851
|
case 74: /* position ::= expr BELOW position */ |
|
2852
|
#line 720 "pikchr.y" |
|
2853
|
{yylhsminor.yy187=yymsp[0].minor.yy187; yylhsminor.yy187.y -= yymsp[-2].minor.yy129;} |
|
2854
|
#line 2854 "pikchr.c" |
|
2855
|
yymsp[-2].minor.yy187 = yylhsminor.yy187; |
|
2856
|
break; |
|
2857
|
case 75: /* position ::= expr LEFT OF position */ |
|
2858
|
#line 721 "pikchr.y" |
|
2859
|
{yylhsminor.yy187=yymsp[0].minor.yy187; yylhsminor.yy187.x -= yymsp[-3].minor.yy129;} |
|
2860
|
#line 2860 "pikchr.c" |
|
2861
|
yymsp[-3].minor.yy187 = yylhsminor.yy187; |
|
2862
|
break; |
|
2863
|
case 76: /* position ::= expr RIGHT OF position */ |
|
2864
|
#line 722 "pikchr.y" |
|
2865
|
{yylhsminor.yy187=yymsp[0].minor.yy187; yylhsminor.yy187.x += yymsp[-3].minor.yy129;} |
|
2866
|
#line 2866 "pikchr.c" |
|
2867
|
yymsp[-3].minor.yy187 = yylhsminor.yy187; |
|
2868
|
break; |
|
2869
|
case 77: /* position ::= expr ON HEADING EDGEPT OF position */ |
|
2870
|
#line 724 "pikchr.y" |
|
2871
|
{yylhsminor.yy187 = pik_position_at_hdg(yymsp[-5].minor.yy129,&yymsp[-2].minor.yy0,yymsp[0].minor.yy187);} |
|
2872
|
#line 2872 "pikchr.c" |
|
2873
|
yymsp[-5].minor.yy187 = yylhsminor.yy187; |
|
2874
|
break; |
|
2875
|
case 78: /* position ::= expr HEADING EDGEPT OF position */ |
|
2876
|
#line 726 "pikchr.y" |
|
2877
|
{yylhsminor.yy187 = pik_position_at_hdg(yymsp[-4].minor.yy129,&yymsp[-2].minor.yy0,yymsp[0].minor.yy187);} |
|
2878
|
#line 2878 "pikchr.c" |
|
2879
|
yymsp[-4].minor.yy187 = yylhsminor.yy187; |
|
2880
|
break; |
|
2881
|
case 79: /* position ::= expr EDGEPT OF position */ |
|
2882
|
#line 728 "pikchr.y" |
|
2883
|
{yylhsminor.yy187 = pik_position_at_hdg(yymsp[-3].minor.yy129,&yymsp[-2].minor.yy0,yymsp[0].minor.yy187);} |
|
2884
|
#line 2884 "pikchr.c" |
|
2885
|
yymsp[-3].minor.yy187 = yylhsminor.yy187; |
|
2886
|
break; |
|
2887
|
case 80: /* position ::= expr ON HEADING expr FROM position */ |
|
2888
|
#line 730 "pikchr.y" |
|
2889
|
{yylhsminor.yy187 = pik_position_at_angle(yymsp[-5].minor.yy129,yymsp[-2].minor.yy129,yymsp[0].minor.yy187);} |
|
2890
|
#line 2890 "pikchr.c" |
|
2891
|
yymsp[-5].minor.yy187 = yylhsminor.yy187; |
|
2892
|
break; |
|
2893
|
case 81: /* position ::= expr HEADING expr FROM position */ |
|
2894
|
#line 732 "pikchr.y" |
|
2895
|
{yylhsminor.yy187 = pik_position_at_angle(yymsp[-4].minor.yy129,yymsp[-2].minor.yy129,yymsp[0].minor.yy187);} |
|
2896
|
#line 2896 "pikchr.c" |
|
2897
|
yymsp[-4].minor.yy187 = yylhsminor.yy187; |
|
2898
|
break; |
|
2899
|
case 82: /* place ::= edge OF object */ |
|
2900
|
#line 744 "pikchr.y" |
|
2901
|
{yylhsminor.yy187 = pik_place_of_elem(p,yymsp[0].minor.yy54,&yymsp[-2].minor.yy0);} |
|
2902
|
#line 2902 "pikchr.c" |
|
2903
|
yymsp[-2].minor.yy187 = yylhsminor.yy187; |
|
2904
|
break; |
|
2905
|
case 83: /* place2 ::= object */ |
|
2906
|
#line 745 "pikchr.y" |
|
2907
|
{yylhsminor.yy187 = pik_place_of_elem(p,yymsp[0].minor.yy54,0);} |
|
2908
|
#line 2908 "pikchr.c" |
|
2909
|
yymsp[0].minor.yy187 = yylhsminor.yy187; |
|
2910
|
break; |
|
2911
|
case 84: /* place2 ::= object DOT_E edge */ |
|
2912
|
#line 746 "pikchr.y" |
|
2913
|
{yylhsminor.yy187 = pik_place_of_elem(p,yymsp[-2].minor.yy54,&yymsp[0].minor.yy0);} |
|
2914
|
#line 2914 "pikchr.c" |
|
2915
|
yymsp[-2].minor.yy187 = yylhsminor.yy187; |
|
2916
|
break; |
|
2917
|
case 85: /* place2 ::= NTH VERTEX OF object */ |
|
2918
|
#line 747 "pikchr.y" |
|
2919
|
{yylhsminor.yy187 = pik_nth_vertex(p,&yymsp[-3].minor.yy0,&yymsp[-2].minor.yy0,yymsp[0].minor.yy54);} |
|
2920
|
#line 2920 "pikchr.c" |
|
2921
|
yymsp[-3].minor.yy187 = yylhsminor.yy187; |
|
2922
|
break; |
|
2923
|
case 86: /* object ::= nth */ |
|
2924
|
#line 759 "pikchr.y" |
|
2925
|
{yylhsminor.yy54 = pik_find_nth(p,0,&yymsp[0].minor.yy0);} |
|
2926
|
#line 2926 "pikchr.c" |
|
2927
|
yymsp[0].minor.yy54 = yylhsminor.yy54; |
|
2928
|
break; |
|
2929
|
case 87: /* object ::= nth OF|IN object */ |
|
2930
|
#line 760 "pikchr.y" |
|
2931
|
{yylhsminor.yy54 = pik_find_nth(p,yymsp[0].minor.yy54,&yymsp[-2].minor.yy0);} |
|
2932
|
#line 2932 "pikchr.c" |
|
2933
|
yymsp[-2].minor.yy54 = yylhsminor.yy54; |
|
2934
|
break; |
|
2935
|
case 88: /* objectname ::= THIS */ |
|
2936
|
#line 762 "pikchr.y" |
|
2937
|
{yymsp[0].minor.yy54 = p->cur;} |
|
2938
|
#line 2938 "pikchr.c" |
|
2939
|
break; |
|
2940
|
case 89: /* objectname ::= PLACENAME */ |
|
2941
|
#line 763 "pikchr.y" |
|
2942
|
{yylhsminor.yy54 = pik_find_byname(p,0,&yymsp[0].minor.yy0);} |
|
2943
|
#line 2943 "pikchr.c" |
|
2944
|
yymsp[0].minor.yy54 = yylhsminor.yy54; |
|
2945
|
break; |
|
2946
|
case 90: /* objectname ::= objectname DOT_U PLACENAME */ |
|
2947
|
#line 765 "pikchr.y" |
|
2948
|
{yylhsminor.yy54 = pik_find_byname(p,yymsp[-2].minor.yy54,&yymsp[0].minor.yy0);} |
|
2949
|
#line 2949 "pikchr.c" |
|
2950
|
yymsp[-2].minor.yy54 = yylhsminor.yy54; |
|
2951
|
break; |
|
2952
|
case 91: /* nth ::= NTH CLASSNAME */ |
|
2953
|
#line 767 "pikchr.y" |
|
2954
|
{yylhsminor.yy0=yymsp[0].minor.yy0; yylhsminor.yy0.eCode = pik_nth_value(p,&yymsp[-1].minor.yy0); } |
|
2955
|
#line 2955 "pikchr.c" |
|
2956
|
yymsp[-1].minor.yy0 = yylhsminor.yy0; |
|
2957
|
break; |
|
2958
|
case 92: /* nth ::= NTH LAST CLASSNAME */ |
|
2959
|
#line 768 "pikchr.y" |
|
2960
|
{yylhsminor.yy0=yymsp[0].minor.yy0; yylhsminor.yy0.eCode = -pik_nth_value(p,&yymsp[-2].minor.yy0); } |
|
2961
|
#line 2961 "pikchr.c" |
|
2962
|
yymsp[-2].minor.yy0 = yylhsminor.yy0; |
|
2963
|
break; |
|
2964
|
case 93: /* nth ::= LAST CLASSNAME */ |
|
2965
|
#line 769 "pikchr.y" |
|
2966
|
{yymsp[-1].minor.yy0=yymsp[0].minor.yy0; yymsp[-1].minor.yy0.eCode = -1;} |
|
2967
|
#line 2967 "pikchr.c" |
|
2968
|
break; |
|
2969
|
case 94: /* nth ::= LAST */ |
|
2970
|
#line 770 "pikchr.y" |
|
2971
|
{yylhsminor.yy0=yymsp[0].minor.yy0; yylhsminor.yy0.eCode = -1;} |
|
2972
|
#line 2972 "pikchr.c" |
|
2973
|
yymsp[0].minor.yy0 = yylhsminor.yy0; |
|
2974
|
break; |
|
2975
|
case 95: /* nth ::= NTH LB RB */ |
|
2976
|
#line 771 "pikchr.y" |
|
2977
|
{yylhsminor.yy0=yymsp[-1].minor.yy0; yylhsminor.yy0.eCode = pik_nth_value(p,&yymsp[-2].minor.yy0);} |
|
2978
|
#line 2978 "pikchr.c" |
|
2979
|
yymsp[-2].minor.yy0 = yylhsminor.yy0; |
|
2980
|
break; |
|
2981
|
case 96: /* nth ::= NTH LAST LB RB */ |
|
2982
|
#line 772 "pikchr.y" |
|
2983
|
{yylhsminor.yy0=yymsp[-1].minor.yy0; yylhsminor.yy0.eCode = -pik_nth_value(p,&yymsp[-3].minor.yy0);} |
|
2984
|
#line 2984 "pikchr.c" |
|
2985
|
yymsp[-3].minor.yy0 = yylhsminor.yy0; |
|
2986
|
break; |
|
2987
|
case 97: /* nth ::= LAST LB RB */ |
|
2988
|
#line 773 "pikchr.y" |
|
2989
|
{yymsp[-2].minor.yy0=yymsp[-1].minor.yy0; yymsp[-2].minor.yy0.eCode = -1; } |
|
2990
|
#line 2990 "pikchr.c" |
|
2991
|
break; |
|
2992
|
case 98: /* expr ::= expr PLUS expr */ |
|
2993
|
#line 775 "pikchr.y" |
|
2994
|
{yylhsminor.yy129=yymsp[-2].minor.yy129+yymsp[0].minor.yy129;} |
|
2995
|
#line 2995 "pikchr.c" |
|
2996
|
yymsp[-2].minor.yy129 = yylhsminor.yy129; |
|
2997
|
break; |
|
2998
|
case 99: /* expr ::= expr MINUS expr */ |
|
2999
|
#line 776 "pikchr.y" |
|
3000
|
{yylhsminor.yy129=yymsp[-2].minor.yy129-yymsp[0].minor.yy129;} |
|
3001
|
#line 3001 "pikchr.c" |
|
3002
|
yymsp[-2].minor.yy129 = yylhsminor.yy129; |
|
3003
|
break; |
|
3004
|
case 100: /* expr ::= expr STAR expr */ |
|
3005
|
#line 777 "pikchr.y" |
|
3006
|
{yylhsminor.yy129=yymsp[-2].minor.yy129*yymsp[0].minor.yy129;} |
|
3007
|
#line 3007 "pikchr.c" |
|
3008
|
yymsp[-2].minor.yy129 = yylhsminor.yy129; |
|
3009
|
break; |
|
3010
|
case 101: /* expr ::= expr SLASH expr */ |
|
3011
|
#line 778 "pikchr.y" |
|
3012
|
{ |
|
3013
|
if( yymsp[0].minor.yy129==0.0 ){ pik_error(p, &yymsp[-1].minor.yy0, "division by zero"); yylhsminor.yy129 = 0.0; } |
|
3014
|
else{ yylhsminor.yy129 = yymsp[-2].minor.yy129/yymsp[0].minor.yy129; } |
|
3015
|
} |
|
3016
|
#line 3016 "pikchr.c" |
|
3017
|
yymsp[-2].minor.yy129 = yylhsminor.yy129; |
|
3018
|
break; |
|
3019
|
case 102: /* expr ::= MINUS expr */ |
|
3020
|
#line 782 "pikchr.y" |
|
3021
|
{yymsp[-1].minor.yy129=-yymsp[0].minor.yy129;} |
|
3022
|
#line 3022 "pikchr.c" |
|
3023
|
break; |
|
3024
|
case 103: /* expr ::= PLUS expr */ |
|
3025
|
#line 783 "pikchr.y" |
|
3026
|
{yymsp[-1].minor.yy129=yymsp[0].minor.yy129;} |
|
3027
|
#line 3027 "pikchr.c" |
|
3028
|
break; |
|
3029
|
case 104: /* expr ::= LP expr RP */ |
|
3030
|
#line 784 "pikchr.y" |
|
3031
|
{yymsp[-2].minor.yy129=yymsp[-1].minor.yy129;} |
|
3032
|
#line 3032 "pikchr.c" |
|
3033
|
break; |
|
3034
|
case 105: /* expr ::= LP FILL|COLOR|THICKNESS RP */ |
|
3035
|
#line 785 "pikchr.y" |
|
3036
|
{yymsp[-2].minor.yy129=pik_get_var(p,&yymsp[-1].minor.yy0);} |
|
3037
|
#line 3037 "pikchr.c" |
|
3038
|
break; |
|
3039
|
case 106: /* expr ::= NUMBER */ |
|
3040
|
#line 786 "pikchr.y" |
|
3041
|
{yylhsminor.yy129=pik_atof(&yymsp[0].minor.yy0);} |
|
3042
|
#line 3042 "pikchr.c" |
|
3043
|
yymsp[0].minor.yy129 = yylhsminor.yy129; |
|
3044
|
break; |
|
3045
|
case 107: /* expr ::= ID */ |
|
3046
|
#line 787 "pikchr.y" |
|
3047
|
{yylhsminor.yy129=pik_get_var(p,&yymsp[0].minor.yy0);} |
|
3048
|
#line 3048 "pikchr.c" |
|
3049
|
yymsp[0].minor.yy129 = yylhsminor.yy129; |
|
3050
|
break; |
|
3051
|
case 108: /* expr ::= FUNC1 LP expr RP */ |
|
3052
|
#line 788 "pikchr.y" |
|
3053
|
{yylhsminor.yy129 = pik_func(p,&yymsp[-3].minor.yy0,yymsp[-1].minor.yy129,0.0);} |
|
3054
|
#line 3054 "pikchr.c" |
|
3055
|
yymsp[-3].minor.yy129 = yylhsminor.yy129; |
|
3056
|
break; |
|
3057
|
case 109: /* expr ::= FUNC2 LP expr COMMA expr RP */ |
|
3058
|
#line 789 "pikchr.y" |
|
3059
|
{yylhsminor.yy129 = pik_func(p,&yymsp[-5].minor.yy0,yymsp[-3].minor.yy129,yymsp[-1].minor.yy129);} |
|
3060
|
#line 3060 "pikchr.c" |
|
3061
|
yymsp[-5].minor.yy129 = yylhsminor.yy129; |
|
3062
|
break; |
|
3063
|
case 110: /* expr ::= DIST LP position COMMA position RP */ |
|
3064
|
#line 790 "pikchr.y" |
|
3065
|
{yymsp[-5].minor.yy129 = pik_dist(&yymsp[-3].minor.yy187,&yymsp[-1].minor.yy187);} |
|
3066
|
#line 3066 "pikchr.c" |
|
3067
|
break; |
|
3068
|
case 111: /* expr ::= place2 DOT_XY X */ |
|
3069
|
#line 791 "pikchr.y" |
|
3070
|
{yylhsminor.yy129 = yymsp[-2].minor.yy187.x;} |
|
3071
|
#line 3071 "pikchr.c" |
|
3072
|
yymsp[-2].minor.yy129 = yylhsminor.yy129; |
|
3073
|
break; |
|
3074
|
case 112: /* expr ::= place2 DOT_XY Y */ |
|
3075
|
#line 792 "pikchr.y" |
|
3076
|
{yylhsminor.yy129 = yymsp[-2].minor.yy187.y;} |
|
3077
|
#line 3077 "pikchr.c" |
|
3078
|
yymsp[-2].minor.yy129 = yylhsminor.yy129; |
|
3079
|
break; |
|
3080
|
case 113: /* expr ::= object DOT_L numproperty */ |
|
3081
|
case 114: /* expr ::= object DOT_L dashproperty */ yytestcase(yyruleno==114); |
|
3082
|
case 115: /* expr ::= object DOT_L colorproperty */ yytestcase(yyruleno==115); |
|
3083
|
#line 793 "pikchr.y" |
|
3084
|
{yylhsminor.yy129=pik_property_of(yymsp[-2].minor.yy54,&yymsp[0].minor.yy0);} |
|
3085
|
#line 3085 "pikchr.c" |
|
3086
|
yymsp[-2].minor.yy129 = yylhsminor.yy129; |
|
3087
|
break; |
|
3088
|
default: |
|
3089
|
/* (116) lvalue ::= ID */ yytestcase(yyruleno==116); |
|
3090
|
/* (117) lvalue ::= FILL */ yytestcase(yyruleno==117); |
|
3091
|
/* (118) lvalue ::= COLOR */ yytestcase(yyruleno==118); |
|
3092
|
/* (119) lvalue ::= THICKNESS */ yytestcase(yyruleno==119); |
|
3093
|
/* (120) rvalue ::= expr */ yytestcase(yyruleno==120); |
|
3094
|
/* (121) print ::= PRINT */ yytestcase(yyruleno==121); |
|
3095
|
/* (122) prlist ::= pritem (OPTIMIZED OUT) */ assert(yyruleno!=122); |
|
3096
|
/* (123) prlist ::= prlist prsep pritem */ yytestcase(yyruleno==123); |
|
3097
|
/* (124) direction ::= UP */ yytestcase(yyruleno==124); |
|
3098
|
/* (125) direction ::= DOWN */ yytestcase(yyruleno==125); |
|
3099
|
/* (126) direction ::= LEFT */ yytestcase(yyruleno==126); |
|
3100
|
/* (127) direction ::= RIGHT */ yytestcase(yyruleno==127); |
|
3101
|
/* (128) optrelexpr ::= relexpr (OPTIMIZED OUT) */ assert(yyruleno!=128); |
|
3102
|
/* (129) attribute_list ::= alist */ yytestcase(yyruleno==129); |
|
3103
|
/* (130) alist ::= */ yytestcase(yyruleno==130); |
|
3104
|
/* (131) alist ::= alist attribute */ yytestcase(yyruleno==131); |
|
3105
|
/* (132) attribute ::= boolproperty (OPTIMIZED OUT) */ assert(yyruleno!=132); |
|
3106
|
/* (133) attribute ::= WITH withclause */ yytestcase(yyruleno==133); |
|
3107
|
/* (134) go ::= GO */ yytestcase(yyruleno==134); |
|
3108
|
/* (135) go ::= */ yytestcase(yyruleno==135); |
|
3109
|
/* (136) even ::= UNTIL EVEN WITH */ yytestcase(yyruleno==136); |
|
3110
|
/* (137) even ::= EVEN WITH */ yytestcase(yyruleno==137); |
|
3111
|
/* (138) dashproperty ::= DOTTED */ yytestcase(yyruleno==138); |
|
3112
|
/* (139) dashproperty ::= DASHED */ yytestcase(yyruleno==139); |
|
3113
|
/* (140) colorproperty ::= FILL */ yytestcase(yyruleno==140); |
|
3114
|
/* (141) colorproperty ::= COLOR */ yytestcase(yyruleno==141); |
|
3115
|
/* (142) position ::= place */ yytestcase(yyruleno==142); |
|
3116
|
/* (143) between ::= WAY BETWEEN */ yytestcase(yyruleno==143); |
|
3117
|
/* (144) between ::= BETWEEN */ yytestcase(yyruleno==144); |
|
3118
|
/* (145) between ::= OF THE WAY BETWEEN */ yytestcase(yyruleno==145); |
|
3119
|
/* (146) place ::= place2 */ yytestcase(yyruleno==146); |
|
3120
|
/* (147) edge ::= CENTER */ yytestcase(yyruleno==147); |
|
3121
|
/* (148) edge ::= EDGEPT */ yytestcase(yyruleno==148); |
|
3122
|
/* (149) edge ::= TOP */ yytestcase(yyruleno==149); |
|
3123
|
/* (150) edge ::= BOTTOM */ yytestcase(yyruleno==150); |
|
3124
|
/* (151) edge ::= START */ yytestcase(yyruleno==151); |
|
3125
|
/* (152) edge ::= END */ yytestcase(yyruleno==152); |
|
3126
|
/* (153) edge ::= RIGHT */ yytestcase(yyruleno==153); |
|
3127
|
/* (154) edge ::= LEFT */ yytestcase(yyruleno==154); |
|
3128
|
/* (155) object ::= objectname */ yytestcase(yyruleno==155); |
|
3129
|
break; |
|
3130
|
/********** End reduce actions ************************************************/ |
|
3131
|
}; |
|
3132
|
assert( yyruleno<sizeof(yyRuleInfoLhs)/sizeof(yyRuleInfoLhs[0]) ); |
|
3133
|
yygoto = yyRuleInfoLhs[yyruleno]; |
|
3134
|
yysize = yyRuleInfoNRhs[yyruleno]; |
|
3135
|
yyact = yy_find_reduce_action(yymsp[yysize].stateno,(YYCODETYPE)yygoto); |
|
3136
|
|
|
3137
|
/* There are no SHIFTREDUCE actions on nonterminals because the table |
|
3138
|
** generator has simplified them to pure REDUCE actions. */ |
|
3139
|
assert( !(yyact>YY_MAX_SHIFT && yyact<=YY_MAX_SHIFTREDUCE) ); |
|
3140
|
|
|
3141
|
/* It is not possible for a REDUCE to be followed by an error */ |
|
3142
|
assert( yyact!=YY_ERROR_ACTION ); |
|
3143
|
|
|
3144
|
yymsp += yysize+1; |
|
3145
|
yypParser->yytos = yymsp; |
|
3146
|
yymsp->stateno = (YYACTIONTYPE)yyact; |
|
3147
|
yymsp->major = (YYCODETYPE)yygoto; |
|
3148
|
yyTraceShift(yypParser, yyact, "... then shift"); |
|
3149
|
return yyact; |
|
3150
|
} |
|
3151
|
|
|
3152
|
/* |
|
3153
|
** The following code executes when the parse fails |
|
3154
|
*/ |
|
3155
|
#ifndef YYNOERRORRECOVERY |
|
3156
|
static void yy_parse_failed( |
|
3157
|
yyParser *yypParser /* The parser */ |
|
3158
|
){ |
|
3159
|
pik_parserARG_FETCH |
|
3160
|
pik_parserCTX_FETCH |
|
3161
|
#ifndef NDEBUG |
|
3162
|
if( yyTraceFILE ){ |
|
3163
|
fprintf(yyTraceFILE,"%sFail!\n",yyTracePrompt); |
|
3164
|
} |
|
3165
|
#endif |
|
3166
|
while( yypParser->yytos>yypParser->yystack ) yy_pop_parser_stack(yypParser); |
|
3167
|
/* Here code is inserted which will be executed whenever the |
|
3168
|
** parser fails */ |
|
3169
|
/************ Begin %parse_failure code ***************************************/ |
|
3170
|
/************ End %parse_failure code *****************************************/ |
|
3171
|
pik_parserARG_STORE /* Suppress warning about unused %extra_argument variable */ |
|
3172
|
pik_parserCTX_STORE |
|
3173
|
} |
|
3174
|
#endif /* YYNOERRORRECOVERY */ |
|
3175
|
|
|
3176
|
/* |
|
3177
|
** The following code executes when a syntax error first occurs. |
|
3178
|
*/ |
|
3179
|
static void yy_syntax_error( |
|
3180
|
yyParser *yypParser, /* The parser */ |
|
3181
|
int yymajor, /* The major type of the error token */ |
|
3182
|
pik_parserTOKENTYPE yyminor /* The minor type of the error token */ |
|
3183
|
){ |
|
3184
|
pik_parserARG_FETCH |
|
3185
|
pik_parserCTX_FETCH |
|
3186
|
#define TOKEN yyminor |
|
3187
|
/************ Begin %syntax_error code ****************************************/ |
|
3188
|
#line 551 "pikchr.y" |
|
3189
|
|
|
3190
|
if( TOKEN.z && TOKEN.z[0] ){ |
|
3191
|
pik_error(p, &TOKEN, "syntax error"); |
|
3192
|
}else{ |
|
3193
|
pik_error(p, 0, "syntax error"); |
|
3194
|
} |
|
3195
|
UNUSED_PARAMETER(yymajor); |
|
3196
|
#line 3196 "pikchr.c" |
|
3197
|
/************ End %syntax_error code ******************************************/ |
|
3198
|
pik_parserARG_STORE /* Suppress warning about unused %extra_argument variable */ |
|
3199
|
pik_parserCTX_STORE |
|
3200
|
} |
|
3201
|
|
|
3202
|
/* |
|
3203
|
** The following is executed when the parser accepts |
|
3204
|
*/ |
|
3205
|
static void yy_accept( |
|
3206
|
yyParser *yypParser /* The parser */ |
|
3207
|
){ |
|
3208
|
pik_parserARG_FETCH |
|
3209
|
pik_parserCTX_FETCH |
|
3210
|
#ifndef NDEBUG |
|
3211
|
if( yyTraceFILE ){ |
|
3212
|
fprintf(yyTraceFILE,"%sAccept!\n",yyTracePrompt); |
|
3213
|
} |
|
3214
|
#endif |
|
3215
|
#ifndef YYNOERRORRECOVERY |
|
3216
|
yypParser->yyerrcnt = -1; |
|
3217
|
#endif |
|
3218
|
assert( yypParser->yytos==yypParser->yystack ); |
|
3219
|
/* Here code is inserted which will be executed whenever the |
|
3220
|
** parser accepts */ |
|
3221
|
/*********** Begin %parse_accept code *****************************************/ |
|
3222
|
/*********** End %parse_accept code *******************************************/ |
|
3223
|
pik_parserARG_STORE /* Suppress warning about unused %extra_argument variable */ |
|
3224
|
pik_parserCTX_STORE |
|
3225
|
} |
|
3226
|
|
|
3227
|
/* The main parser program. |
|
3228
|
** The first argument is a pointer to a structure obtained from |
|
3229
|
** "pik_parserAlloc" which describes the current state of the parser. |
|
3230
|
** The second argument is the major token number. The third is |
|
3231
|
** the minor token. The fourth optional argument is whatever the |
|
3232
|
** user wants (and specified in the grammar) and is available for |
|
3233
|
** use by the action routines. |
|
3234
|
** |
|
3235
|
** Inputs: |
|
3236
|
** <ul> |
|
3237
|
** <li> A pointer to the parser (an opaque structure.) |
|
3238
|
** <li> The major token number. |
|
3239
|
** <li> The minor token number. |
|
3240
|
** <li> An option argument of a grammar-specified type. |
|
3241
|
** </ul> |
|
3242
|
** |
|
3243
|
** Outputs: |
|
3244
|
** None. |
|
3245
|
*/ |
|
3246
|
void pik_parser( |
|
3247
|
void *yyp, /* The parser */ |
|
3248
|
int yymajor, /* The major token code number */ |
|
3249
|
pik_parserTOKENTYPE yyminor /* The value for the token */ |
|
3250
|
pik_parserARG_PDECL /* Optional %extra_argument parameter */ |
|
3251
|
){ |
|
3252
|
YYMINORTYPE yyminorunion; |
|
3253
|
YYACTIONTYPE yyact; /* The parser action. */ |
|
3254
|
#if !defined(YYERRORSYMBOL) && !defined(YYNOERRORRECOVERY) |
|
3255
|
int yyendofinput; /* True if we are at the end of input */ |
|
3256
|
#endif |
|
3257
|
#ifdef YYERRORSYMBOL |
|
3258
|
int yyerrorhit = 0; /* True if yymajor has invoked an error */ |
|
3259
|
#endif |
|
3260
|
yyParser *yypParser = (yyParser*)yyp; /* The parser */ |
|
3261
|
pik_parserCTX_FETCH |
|
3262
|
pik_parserARG_STORE |
|
3263
|
|
|
3264
|
assert( yypParser->yytos!=0 ); |
|
3265
|
#if !defined(YYERRORSYMBOL) && !defined(YYNOERRORRECOVERY) |
|
3266
|
yyendofinput = (yymajor==0); |
|
3267
|
#endif |
|
3268
|
|
|
3269
|
yyact = yypParser->yytos->stateno; |
|
3270
|
#ifndef NDEBUG |
|
3271
|
if( yyTraceFILE ){ |
|
3272
|
if( yyact < YY_MIN_REDUCE ){ |
|
3273
|
fprintf(yyTraceFILE,"%sInput '%s' in state %d\n", |
|
3274
|
yyTracePrompt,yyTokenName[yymajor],yyact); |
|
3275
|
}else{ |
|
3276
|
fprintf(yyTraceFILE,"%sInput '%s' with pending reduce %d\n", |
|
3277
|
yyTracePrompt,yyTokenName[yymajor],yyact-YY_MIN_REDUCE); |
|
3278
|
} |
|
3279
|
} |
|
3280
|
#endif |
|
3281
|
|
|
3282
|
while(1){ /* Exit by "break" */ |
|
3283
|
assert( yypParser->yytos>=yypParser->yystack ); |
|
3284
|
assert( yyact==yypParser->yytos->stateno ); |
|
3285
|
yyact = yy_find_shift_action((YYCODETYPE)yymajor,yyact); |
|
3286
|
if( yyact >= YY_MIN_REDUCE ){ |
|
3287
|
unsigned int yyruleno = yyact - YY_MIN_REDUCE; /* Reduce by this rule */ |
|
3288
|
#ifndef NDEBUG |
|
3289
|
assert( yyruleno<(int)(sizeof(yyRuleName)/sizeof(yyRuleName[0])) ); |
|
3290
|
if( yyTraceFILE ){ |
|
3291
|
int yysize = yyRuleInfoNRhs[yyruleno]; |
|
3292
|
if( yysize ){ |
|
3293
|
fprintf(yyTraceFILE, "%sReduce %d [%s]%s, pop back to state %d.\n", |
|
3294
|
yyTracePrompt, |
|
3295
|
yyruleno, yyRuleName[yyruleno], |
|
3296
|
yyruleno<YYNRULE_WITH_ACTION ? "" : " without external action", |
|
3297
|
yypParser->yytos[yysize].stateno); |
|
3298
|
}else{ |
|
3299
|
fprintf(yyTraceFILE, "%sReduce %d [%s]%s.\n", |
|
3300
|
yyTracePrompt, yyruleno, yyRuleName[yyruleno], |
|
3301
|
yyruleno<YYNRULE_WITH_ACTION ? "" : " without external action"); |
|
3302
|
} |
|
3303
|
} |
|
3304
|
#endif /* NDEBUG */ |
|
3305
|
|
|
3306
|
/* Check that the stack is large enough to grow by a single entry |
|
3307
|
** if the RHS of the rule is empty. This ensures that there is room |
|
3308
|
** enough on the stack to push the LHS value */ |
|
3309
|
if( yyRuleInfoNRhs[yyruleno]==0 ){ |
|
3310
|
#ifdef YYTRACKMAXSTACKDEPTH |
|
3311
|
if( (int)(yypParser->yytos - yypParser->yystack)>yypParser->yyhwm ){ |
|
3312
|
yypParser->yyhwm++; |
|
3313
|
assert( yypParser->yyhwm == |
|
3314
|
(int)(yypParser->yytos - yypParser->yystack)); |
|
3315
|
} |
|
3316
|
#endif |
|
3317
|
if( yypParser->yytos>=yypParser->yystackEnd ){ |
|
3318
|
if( yyGrowStack(yypParser) ){ |
|
3319
|
yyStackOverflow(yypParser); |
|
3320
|
break; |
|
3321
|
} |
|
3322
|
} |
|
3323
|
} |
|
3324
|
yyact = yy_reduce(yypParser,yyruleno,yymajor,yyminor pik_parserCTX_PARAM); |
|
3325
|
}else if( yyact <= YY_MAX_SHIFTREDUCE ){ |
|
3326
|
yy_shift(yypParser,yyact,(YYCODETYPE)yymajor,yyminor); |
|
3327
|
#ifndef YYNOERRORRECOVERY |
|
3328
|
yypParser->yyerrcnt--; |
|
3329
|
#endif |
|
3330
|
break; |
|
3331
|
}else if( yyact==YY_ACCEPT_ACTION ){ |
|
3332
|
yypParser->yytos--; |
|
3333
|
yy_accept(yypParser); |
|
3334
|
return; |
|
3335
|
}else{ |
|
3336
|
assert( yyact == YY_ERROR_ACTION ); |
|
3337
|
yyminorunion.yy0 = yyminor; |
|
3338
|
#ifdef YYERRORSYMBOL |
|
3339
|
int yymx; |
|
3340
|
#endif |
|
3341
|
#ifndef NDEBUG |
|
3342
|
if( yyTraceFILE ){ |
|
3343
|
fprintf(yyTraceFILE,"%sSyntax Error!\n",yyTracePrompt); |
|
3344
|
} |
|
3345
|
#endif |
|
3346
|
#ifdef YYERRORSYMBOL |
|
3347
|
/* A syntax error has occurred. |
|
3348
|
** The response to an error depends upon whether or not the |
|
3349
|
** grammar defines an error token "ERROR". |
|
3350
|
** |
|
3351
|
** This is what we do if the grammar does define ERROR: |
|
3352
|
** |
|
3353
|
** * Call the %syntax_error function. |
|
3354
|
** |
|
3355
|
** * Begin popping the stack until we enter a state where |
|
3356
|
** it is legal to shift the error symbol, then shift |
|
3357
|
** the error symbol. |
|
3358
|
** |
|
3359
|
** * Set the error count to three. |
|
3360
|
** |
|
3361
|
** * Begin accepting and shifting new tokens. No new error |
|
3362
|
** processing will occur until three tokens have been |
|
3363
|
** shifted successfully. |
|
3364
|
** |
|
3365
|
*/ |
|
3366
|
if( yypParser->yyerrcnt<0 ){ |
|
3367
|
yy_syntax_error(yypParser,yymajor,yyminor); |
|
3368
|
} |
|
3369
|
yymx = yypParser->yytos->major; |
|
3370
|
if( yymx==YYERRORSYMBOL || yyerrorhit ){ |
|
3371
|
#ifndef NDEBUG |
|
3372
|
if( yyTraceFILE ){ |
|
3373
|
fprintf(yyTraceFILE,"%sDiscard input token %s\n", |
|
3374
|
yyTracePrompt,yyTokenName[yymajor]); |
|
3375
|
} |
|
3376
|
#endif |
|
3377
|
yy_destructor(yypParser, (YYCODETYPE)yymajor, &yyminorunion); |
|
3378
|
yymajor = YYNOCODE; |
|
3379
|
}else{ |
|
3380
|
while( yypParser->yytos > yypParser->yystack ){ |
|
3381
|
yyact = yy_find_reduce_action(yypParser->yytos->stateno, |
|
3382
|
YYERRORSYMBOL); |
|
3383
|
if( yyact<=YY_MAX_SHIFTREDUCE ) break; |
|
3384
|
yy_pop_parser_stack(yypParser); |
|
3385
|
} |
|
3386
|
if( yypParser->yytos <= yypParser->yystack || yymajor==0 ){ |
|
3387
|
yy_destructor(yypParser,(YYCODETYPE)yymajor,&yyminorunion); |
|
3388
|
yy_parse_failed(yypParser); |
|
3389
|
#ifndef YYNOERRORRECOVERY |
|
3390
|
yypParser->yyerrcnt = -1; |
|
3391
|
#endif |
|
3392
|
yymajor = YYNOCODE; |
|
3393
|
}else if( yymx!=YYERRORSYMBOL ){ |
|
3394
|
yy_shift(yypParser,yyact,YYERRORSYMBOL,yyminor); |
|
3395
|
} |
|
3396
|
} |
|
3397
|
yypParser->yyerrcnt = 3; |
|
3398
|
yyerrorhit = 1; |
|
3399
|
if( yymajor==YYNOCODE ) break; |
|
3400
|
yyact = yypParser->yytos->stateno; |
|
3401
|
#elif defined(YYNOERRORRECOVERY) |
|
3402
|
/* If the YYNOERRORRECOVERY macro is defined, then do not attempt to |
|
3403
|
** do any kind of error recovery. Instead, simply invoke the syntax |
|
3404
|
** error routine and continue going as if nothing had happened. |
|
3405
|
** |
|
3406
|
** Applications can set this macro (for example inside %include) if |
|
3407
|
** they intend to abandon the parse upon the first syntax error seen. |
|
3408
|
*/ |
|
3409
|
yy_syntax_error(yypParser,yymajor, yyminor); |
|
3410
|
yy_destructor(yypParser,(YYCODETYPE)yymajor,&yyminorunion); |
|
3411
|
break; |
|
3412
|
#else /* YYERRORSYMBOL is not defined */ |
|
3413
|
/* This is what we do if the grammar does not define ERROR: |
|
3414
|
** |
|
3415
|
** * Report an error message, and throw away the input token. |
|
3416
|
** |
|
3417
|
** * If the input token is $, then fail the parse. |
|
3418
|
** |
|
3419
|
** As before, subsequent error messages are suppressed until |
|
3420
|
** three input tokens have been successfully shifted. |
|
3421
|
*/ |
|
3422
|
if( yypParser->yyerrcnt<=0 ){ |
|
3423
|
yy_syntax_error(yypParser,yymajor, yyminor); |
|
3424
|
} |
|
3425
|
yypParser->yyerrcnt = 3; |
|
3426
|
yy_destructor(yypParser,(YYCODETYPE)yymajor,&yyminorunion); |
|
3427
|
if( yyendofinput ){ |
|
3428
|
yy_parse_failed(yypParser); |
|
3429
|
#ifndef YYNOERRORRECOVERY |
|
3430
|
yypParser->yyerrcnt = -1; |
|
3431
|
#endif |
|
3432
|
} |
|
3433
|
break; |
|
3434
|
#endif |
|
3435
|
} |
|
3436
|
} |
|
3437
|
#ifndef NDEBUG |
|
3438
|
if( yyTraceFILE ){ |
|
3439
|
yyStackEntry *i; |
|
3440
|
char cDiv = '['; |
|
3441
|
fprintf(yyTraceFILE,"%sReturn. Stack=",yyTracePrompt); |
|
3442
|
for(i=&yypParser->yystack[1]; i<=yypParser->yytos; i++){ |
|
3443
|
fprintf(yyTraceFILE,"%c%s", cDiv, yyTokenName[i->major]); |
|
3444
|
cDiv = ' '; |
|
3445
|
} |
|
3446
|
fprintf(yyTraceFILE,"]\n"); |
|
3447
|
} |
|
3448
|
#endif |
|
3449
|
return; |
|
3450
|
} |
|
3451
|
|
|
3452
|
/* |
|
3453
|
** Return the fallback token corresponding to canonical token iToken, or |
|
3454
|
** 0 if iToken has no fallback. |
|
3455
|
*/ |
|
3456
|
int pik_parserFallback(int iToken){ |
|
3457
|
#ifdef YYFALLBACK |
|
3458
|
assert( iToken<(int)(sizeof(yyFallback)/sizeof(yyFallback[0])) ); |
|
3459
|
return yyFallback[iToken]; |
|
3460
|
#else |
|
3461
|
(void)iToken; |
|
3462
|
return 0; |
|
3463
|
#endif |
|
3464
|
} |
|
3465
|
#line 798 "pikchr.y" |
|
3466
|
|
|
3467
|
|
|
3468
|
|
|
3469
|
/* Chart of the 148 official CSS color names with their |
|
3470
|
** corresponding RGB values thru Color Module Level 4: |
|
3471
|
** https://developer.mozilla.org/en-US/docs/Web/CSS/color_value |
|
3472
|
** |
|
3473
|
** Two new names "None" and "Off" are added with a value |
|
3474
|
** of -1. |
|
3475
|
*/ |
|
3476
|
static const struct { |
|
3477
|
const char *zName; /* Name of the color */ |
|
3478
|
int val; /* RGB value */ |
|
3479
|
} aColor[] = { |
|
3480
|
{ "AliceBlue", 0xf0f8ff }, |
|
3481
|
{ "AntiqueWhite", 0xfaebd7 }, |
|
3482
|
{ "Aqua", 0x00ffff }, |
|
3483
|
{ "Aquamarine", 0x7fffd4 }, |
|
3484
|
{ "Azure", 0xf0ffff }, |
|
3485
|
{ "Beige", 0xf5f5dc }, |
|
3486
|
{ "Bisque", 0xffe4c4 }, |
|
3487
|
{ "Black", 0x000000 }, |
|
3488
|
{ "BlanchedAlmond", 0xffebcd }, |
|
3489
|
{ "Blue", 0x0000ff }, |
|
3490
|
{ "BlueViolet", 0x8a2be2 }, |
|
3491
|
{ "Brown", 0xa52a2a }, |
|
3492
|
{ "BurlyWood", 0xdeb887 }, |
|
3493
|
{ "CadetBlue", 0x5f9ea0 }, |
|
3494
|
{ "Chartreuse", 0x7fff00 }, |
|
3495
|
{ "Chocolate", 0xd2691e }, |
|
3496
|
{ "Coral", 0xff7f50 }, |
|
3497
|
{ "CornflowerBlue", 0x6495ed }, |
|
3498
|
{ "Cornsilk", 0xfff8dc }, |
|
3499
|
{ "Crimson", 0xdc143c }, |
|
3500
|
{ "Cyan", 0x00ffff }, |
|
3501
|
{ "DarkBlue", 0x00008b }, |
|
3502
|
{ "DarkCyan", 0x008b8b }, |
|
3503
|
{ "DarkGoldenrod", 0xb8860b }, |
|
3504
|
{ "DarkGray", 0xa9a9a9 }, |
|
3505
|
{ "DarkGreen", 0x006400 }, |
|
3506
|
{ "DarkGrey", 0xa9a9a9 }, |
|
3507
|
{ "DarkKhaki", 0xbdb76b }, |
|
3508
|
{ "DarkMagenta", 0x8b008b }, |
|
3509
|
{ "DarkOliveGreen", 0x556b2f }, |
|
3510
|
{ "DarkOrange", 0xff8c00 }, |
|
3511
|
{ "DarkOrchid", 0x9932cc }, |
|
3512
|
{ "DarkRed", 0x8b0000 }, |
|
3513
|
{ "DarkSalmon", 0xe9967a }, |
|
3514
|
{ "DarkSeaGreen", 0x8fbc8f }, |
|
3515
|
{ "DarkSlateBlue", 0x483d8b }, |
|
3516
|
{ "DarkSlateGray", 0x2f4f4f }, |
|
3517
|
{ "DarkSlateGrey", 0x2f4f4f }, |
|
3518
|
{ "DarkTurquoise", 0x00ced1 }, |
|
3519
|
{ "DarkViolet", 0x9400d3 }, |
|
3520
|
{ "DeepPink", 0xff1493 }, |
|
3521
|
{ "DeepSkyBlue", 0x00bfff }, |
|
3522
|
{ "DimGray", 0x696969 }, |
|
3523
|
{ "DimGrey", 0x696969 }, |
|
3524
|
{ "DodgerBlue", 0x1e90ff }, |
|
3525
|
{ "Firebrick", 0xb22222 }, |
|
3526
|
{ "FloralWhite", 0xfffaf0 }, |
|
3527
|
{ "ForestGreen", 0x228b22 }, |
|
3528
|
{ "Fuchsia", 0xff00ff }, |
|
3529
|
{ "Gainsboro", 0xdcdcdc }, |
|
3530
|
{ "GhostWhite", 0xf8f8ff }, |
|
3531
|
{ "Gold", 0xffd700 }, |
|
3532
|
{ "Goldenrod", 0xdaa520 }, |
|
3533
|
{ "Gray", 0x808080 }, |
|
3534
|
{ "Green", 0x008000 }, |
|
3535
|
{ "GreenYellow", 0xadff2f }, |
|
3536
|
{ "Grey", 0x808080 }, |
|
3537
|
{ "Honeydew", 0xf0fff0 }, |
|
3538
|
{ "HotPink", 0xff69b4 }, |
|
3539
|
{ "IndianRed", 0xcd5c5c }, |
|
3540
|
{ "Indigo", 0x4b0082 }, |
|
3541
|
{ "Ivory", 0xfffff0 }, |
|
3542
|
{ "Khaki", 0xf0e68c }, |
|
3543
|
{ "Lavender", 0xe6e6fa }, |
|
3544
|
{ "LavenderBlush", 0xfff0f5 }, |
|
3545
|
{ "LawnGreen", 0x7cfc00 }, |
|
3546
|
{ "LemonChiffon", 0xfffacd }, |
|
3547
|
{ "LightBlue", 0xadd8e6 }, |
|
3548
|
{ "LightCoral", 0xf08080 }, |
|
3549
|
{ "LightCyan", 0xe0ffff }, |
|
3550
|
{ "LightGoldenrodYellow", 0xfafad2 }, |
|
3551
|
{ "LightGray", 0xd3d3d3 }, |
|
3552
|
{ "LightGreen", 0x90ee90 }, |
|
3553
|
{ "LightGrey", 0xd3d3d3 }, |
|
3554
|
{ "LightPink", 0xffb6c1 }, |
|
3555
|
{ "LightSalmon", 0xffa07a }, |
|
3556
|
{ "LightSeaGreen", 0x20b2aa }, |
|
3557
|
{ "LightSkyBlue", 0x87cefa }, |
|
3558
|
{ "LightSlateGray", 0x778899 }, |
|
3559
|
{ "LightSlateGrey", 0x778899 }, |
|
3560
|
{ "LightSteelBlue", 0xb0c4de }, |
|
3561
|
{ "LightYellow", 0xffffe0 }, |
|
3562
|
{ "Lime", 0x00ff00 }, |
|
3563
|
{ "LimeGreen", 0x32cd32 }, |
|
3564
|
{ "Linen", 0xfaf0e6 }, |
|
3565
|
{ "Magenta", 0xff00ff }, |
|
3566
|
{ "Maroon", 0x800000 }, |
|
3567
|
{ "MediumAquamarine", 0x66cdaa }, |
|
3568
|
{ "MediumBlue", 0x0000cd }, |
|
3569
|
{ "MediumOrchid", 0xba55d3 }, |
|
3570
|
{ "MediumPurple", 0x9370db }, |
|
3571
|
{ "MediumSeaGreen", 0x3cb371 }, |
|
3572
|
{ "MediumSlateBlue", 0x7b68ee }, |
|
3573
|
{ "MediumSpringGreen", 0x00fa9a }, |
|
3574
|
{ "MediumTurquoise", 0x48d1cc }, |
|
3575
|
{ "MediumVioletRed", 0xc71585 }, |
|
3576
|
{ "MidnightBlue", 0x191970 }, |
|
3577
|
{ "MintCream", 0xf5fffa }, |
|
3578
|
{ "MistyRose", 0xffe4e1 }, |
|
3579
|
{ "Moccasin", 0xffe4b5 }, |
|
3580
|
{ "NavajoWhite", 0xffdead }, |
|
3581
|
{ "Navy", 0x000080 }, |
|
3582
|
{ "None", -1 }, /* Non-standard addition */ |
|
3583
|
{ "Off", -1 }, /* Non-standard addition */ |
|
3584
|
{ "OldLace", 0xfdf5e6 }, |
|
3585
|
{ "Olive", 0x808000 }, |
|
3586
|
{ "OliveDrab", 0x6b8e23 }, |
|
3587
|
{ "Orange", 0xffa500 }, |
|
3588
|
{ "OrangeRed", 0xff4500 }, |
|
3589
|
{ "Orchid", 0xda70d6 }, |
|
3590
|
{ "PaleGoldenrod", 0xeee8aa }, |
|
3591
|
{ "PaleGreen", 0x98fb98 }, |
|
3592
|
{ "PaleTurquoise", 0xafeeee }, |
|
3593
|
{ "PaleVioletRed", 0xdb7093 }, |
|
3594
|
{ "PapayaWhip", 0xffefd5 }, |
|
3595
|
{ "PeachPuff", 0xffdab9 }, |
|
3596
|
{ "Peru", 0xcd853f }, |
|
3597
|
{ "Pink", 0xffc0cb }, |
|
3598
|
{ "Plum", 0xdda0dd }, |
|
3599
|
{ "PowderBlue", 0xb0e0e6 }, |
|
3600
|
{ "Purple", 0x800080 }, |
|
3601
|
{ "RebeccaPurple", 0x663399 }, |
|
3602
|
{ "Red", 0xff0000 }, |
|
3603
|
{ "RosyBrown", 0xbc8f8f }, |
|
3604
|
{ "RoyalBlue", 0x4169e1 }, |
|
3605
|
{ "SaddleBrown", 0x8b4513 }, |
|
3606
|
{ "Salmon", 0xfa8072 }, |
|
3607
|
{ "SandyBrown", 0xf4a460 }, |
|
3608
|
{ "SeaGreen", 0x2e8b57 }, |
|
3609
|
{ "Seashell", 0xfff5ee }, |
|
3610
|
{ "Sienna", 0xa0522d }, |
|
3611
|
{ "Silver", 0xc0c0c0 }, |
|
3612
|
{ "SkyBlue", 0x87ceeb }, |
|
3613
|
{ "SlateBlue", 0x6a5acd }, |
|
3614
|
{ "SlateGray", 0x708090 }, |
|
3615
|
{ "SlateGrey", 0x708090 }, |
|
3616
|
{ "Snow", 0xfffafa }, |
|
3617
|
{ "SpringGreen", 0x00ff7f }, |
|
3618
|
{ "SteelBlue", 0x4682b4 }, |
|
3619
|
{ "Tan", 0xd2b48c }, |
|
3620
|
{ "Teal", 0x008080 }, |
|
3621
|
{ "Thistle", 0xd8bfd8 }, |
|
3622
|
{ "Tomato", 0xff6347 }, |
|
3623
|
{ "Turquoise", 0x40e0d0 }, |
|
3624
|
{ "Violet", 0xee82ee }, |
|
3625
|
{ "Wheat", 0xf5deb3 }, |
|
3626
|
{ "White", 0xffffff }, |
|
3627
|
{ "WhiteSmoke", 0xf5f5f5 }, |
|
3628
|
{ "Yellow", 0xffff00 }, |
|
3629
|
{ "YellowGreen", 0x9acd32 }, |
|
3630
|
}; |
|
3631
|
|
|
3632
|
/* Built-in variable names. |
|
3633
|
** |
|
3634
|
** This array is constant. When a script changes the value of one of |
|
3635
|
** these built-ins, a new PVar record is added at the head of |
|
3636
|
** the Pik.pVar list, which is searched first. Thus the new PVar entry |
|
3637
|
** will override this default value. |
|
3638
|
** |
|
3639
|
** Units are in inches, except for "color" and "fill" which are |
|
3640
|
** interpreted as 24-bit RGB values. |
|
3641
|
** |
|
3642
|
** Binary search used. Must be kept in sorted order. |
|
3643
|
*/ |
|
3644
|
static const struct { const char *zName; PNum val; } aBuiltin[] = { |
|
3645
|
{ "arcrad", 0.25 }, |
|
3646
|
{ "arrowhead", 2.0 }, |
|
3647
|
{ "arrowht", 0.08 }, |
|
3648
|
{ "arrowwid", 0.06 }, |
|
3649
|
{ "boxht", 0.5 }, |
|
3650
|
{ "boxrad", 0.0 }, |
|
3651
|
{ "boxwid", 0.75 }, |
|
3652
|
{ "charht", 0.14 }, |
|
3653
|
{ "charwid", 0.08 }, |
|
3654
|
{ "circlerad", 0.25 }, |
|
3655
|
{ "color", 0.0 }, |
|
3656
|
{ "cylht", 0.5 }, |
|
3657
|
{ "cylrad", 0.075 }, |
|
3658
|
{ "cylwid", 0.75 }, |
|
3659
|
{ "dashwid", 0.05 }, |
|
3660
|
{ "diamondht", 0.75 }, |
|
3661
|
{ "diamondwid", 1.0 }, |
|
3662
|
{ "dotrad", 0.015 }, |
|
3663
|
{ "ellipseht", 0.5 }, |
|
3664
|
{ "ellipsewid", 0.75 }, |
|
3665
|
{ "fileht", 0.75 }, |
|
3666
|
{ "filerad", 0.15 }, |
|
3667
|
{ "filewid", 0.5 }, |
|
3668
|
{ "fill", -1.0 }, |
|
3669
|
{ "lineht", 0.5 }, |
|
3670
|
{ "linewid", 0.5 }, |
|
3671
|
{ "movewid", 0.5 }, |
|
3672
|
{ "ovalht", 0.5 }, |
|
3673
|
{ "ovalwid", 1.0 }, |
|
3674
|
{ "scale", 1.0 }, |
|
3675
|
{ "textht", 0.5 }, |
|
3676
|
{ "textwid", 0.75 }, |
|
3677
|
{ "thickness", 0.015 }, |
|
3678
|
}; |
|
3679
|
|
|
3680
|
|
|
3681
|
/* Methods for the "arc" class */ |
|
3682
|
static void arcInit(Pik *p, PObj *pObj){ |
|
3683
|
pObj->w = pik_value(p, "arcrad",6,0); |
|
3684
|
pObj->h = pObj->w; |
|
3685
|
} |
|
3686
|
/* Hack: Arcs are here rendered as quadratic Bezier curves rather |
|
3687
|
** than true arcs. Multiple reasons: (1) the legacy-PIC parameters |
|
3688
|
** that control arcs are obscure and I could not figure out what they |
|
3689
|
** mean based on available documentation. (2) Arcs are rarely used, |
|
3690
|
** and so do not seem that important. |
|
3691
|
*/ |
|
3692
|
static PPoint arcControlPoint(int cw, PPoint f, PPoint t){ |
|
3693
|
PPoint m; |
|
3694
|
PNum dx, dy; |
|
3695
|
m.x = 0.5*(f.x+t.x); |
|
3696
|
m.y = 0.5*(f.y+t.y); |
|
3697
|
dx = t.x - f.x; |
|
3698
|
dy = t.y - f.y; |
|
3699
|
if( cw ){ |
|
3700
|
m.x -= 0.5*dy; |
|
3701
|
m.y += 0.5*dx; |
|
3702
|
}else{ |
|
3703
|
m.x += 0.5*dy; |
|
3704
|
m.y -= 0.5*dx; |
|
3705
|
} |
|
3706
|
return m; |
|
3707
|
} |
|
3708
|
static void arcCheck(Pik *p, PObj *pObj){ |
|
3709
|
PPoint f, m, t; |
|
3710
|
PNum sw; |
|
3711
|
int i; |
|
3712
|
if( p->nTPath>2 ){ |
|
3713
|
pik_error(p, &pObj->errTok, "arc geometry error"); |
|
3714
|
return; |
|
3715
|
} |
|
3716
|
f = p->aTPath[0]; |
|
3717
|
t = p->aTPath[1]; |
|
3718
|
m = arcControlPoint(pObj->cw, f, t); |
|
3719
|
sw = pObj->sw; |
|
3720
|
for(i=1; i<16; i++){ |
|
3721
|
PNum t1, t2, a, b, c, x, y; |
|
3722
|
t1 = 0.0625*i; |
|
3723
|
t2 = 1.0 - t1; |
|
3724
|
a = t2*t2; |
|
3725
|
b = 2*t1*t2; |
|
3726
|
c = t1*t1; |
|
3727
|
x = a*f.x + b*m.x + c*t.x; |
|
3728
|
y = a*f.y + b*m.y + c*t.y; |
|
3729
|
pik_bbox_addellipse(&pObj->bbox, x, y, sw, sw); |
|
3730
|
} |
|
3731
|
} |
|
3732
|
static void arcRender(Pik *p, PObj *pObj){ |
|
3733
|
PPoint f, m, t; |
|
3734
|
if( pObj->nPath<2 ) return; |
|
3735
|
if( pObj->sw<0.0 ) return; |
|
3736
|
f = pObj->aPath[0]; |
|
3737
|
t = pObj->aPath[1]; |
|
3738
|
m = arcControlPoint(pObj->cw,f,t); |
|
3739
|
if( pObj->larrow ){ |
|
3740
|
pik_draw_arrowhead(p,&m,&f,pObj); |
|
3741
|
} |
|
3742
|
if( pObj->rarrow ){ |
|
3743
|
pik_draw_arrowhead(p,&m,&t,pObj); |
|
3744
|
} |
|
3745
|
pik_append_xy(p,"<path d=\"M", f.x, f.y); |
|
3746
|
pik_append_xy(p,"Q", m.x, m.y); |
|
3747
|
pik_append_xy(p," ", t.x, t.y); |
|
3748
|
pik_append(p,"\" ",2); |
|
3749
|
pik_append_style(p,pObj,0); |
|
3750
|
pik_append(p,"\" />\n", -1); |
|
3751
|
|
|
3752
|
pik_append_txt(p, pObj, 0); |
|
3753
|
} |
|
3754
|
|
|
3755
|
|
|
3756
|
/* Methods for the "arrow" class */ |
|
3757
|
static void arrowInit(Pik *p, PObj *pObj){ |
|
3758
|
pObj->w = pik_value(p, "linewid",7,0); |
|
3759
|
pObj->h = pik_value(p, "lineht",6,0); |
|
3760
|
pObj->rad = pik_value(p, "linerad",7,0); |
|
3761
|
pObj->rarrow = 1; |
|
3762
|
} |
|
3763
|
|
|
3764
|
/* Methods for the "box" class */ |
|
3765
|
static void boxInit(Pik *p, PObj *pObj){ |
|
3766
|
pObj->w = pik_value(p, "boxwid",6,0); |
|
3767
|
pObj->h = pik_value(p, "boxht",5,0); |
|
3768
|
pObj->rad = pik_value(p, "boxrad",6,0); |
|
3769
|
} |
|
3770
|
/* Return offset from the center of the box to the compass point |
|
3771
|
** given by parameter cp */ |
|
3772
|
static PPoint boxOffset(Pik *p, PObj *pObj, int cp){ |
|
3773
|
PPoint pt = cZeroPoint; |
|
3774
|
PNum w2 = 0.5*pObj->w; |
|
3775
|
PNum h2 = 0.5*pObj->h; |
|
3776
|
PNum rad = pObj->rad; |
|
3777
|
PNum rx; |
|
3778
|
if( rad<=0.0 ){ |
|
3779
|
rx = 0.0; |
|
3780
|
}else{ |
|
3781
|
if( rad>w2 ) rad = w2; |
|
3782
|
if( rad>h2 ) rad = h2; |
|
3783
|
rx = 0.29289321881345252392*rad; |
|
3784
|
} |
|
3785
|
switch( cp ){ |
|
3786
|
case CP_C: break; |
|
3787
|
case CP_N: pt.x = 0.0; pt.y = h2; break; |
|
3788
|
case CP_NE: pt.x = w2-rx; pt.y = h2-rx; break; |
|
3789
|
case CP_E: pt.x = w2; pt.y = 0.0; break; |
|
3790
|
case CP_SE: pt.x = w2-rx; pt.y = rx-h2; break; |
|
3791
|
case CP_S: pt.x = 0.0; pt.y = -h2; break; |
|
3792
|
case CP_SW: pt.x = rx-w2; pt.y = rx-h2; break; |
|
3793
|
case CP_W: pt.x = -w2; pt.y = 0.0; break; |
|
3794
|
case CP_NW: pt.x = rx-w2; pt.y = h2-rx; break; |
|
3795
|
default: assert(0); |
|
3796
|
} |
|
3797
|
UNUSED_PARAMETER(p); |
|
3798
|
return pt; |
|
3799
|
} |
|
3800
|
static PPoint boxChop(Pik *p, PObj *pObj, PPoint *pPt){ |
|
3801
|
PNum dx, dy; |
|
3802
|
int cp = CP_C; |
|
3803
|
PPoint chop = pObj->ptAt; |
|
3804
|
if( pObj->w<=0.0 ) return chop; |
|
3805
|
if( pObj->h<=0.0 ) return chop; |
|
3806
|
dx = (pPt->x - pObj->ptAt.x)*pObj->h/pObj->w; |
|
3807
|
dy = (pPt->y - pObj->ptAt.y); |
|
3808
|
if( dx>0.0 ){ |
|
3809
|
if( dy>=2.414*dx ){ |
|
3810
|
cp = CP_N; |
|
3811
|
}else if( dy>=0.414*dx ){ |
|
3812
|
cp = CP_NE; |
|
3813
|
}else if( dy>=-0.414*dx ){ |
|
3814
|
cp = CP_E; |
|
3815
|
}else if( dy>-2.414*dx ){ |
|
3816
|
cp = CP_SE; |
|
3817
|
}else{ |
|
3818
|
cp = CP_S; |
|
3819
|
} |
|
3820
|
}else{ |
|
3821
|
if( dy>=-2.414*dx ){ |
|
3822
|
cp = CP_N; |
|
3823
|
}else if( dy>=-0.414*dx ){ |
|
3824
|
cp = CP_NW; |
|
3825
|
}else if( dy>=0.414*dx ){ |
|
3826
|
cp = CP_W; |
|
3827
|
}else if( dy>2.414*dx ){ |
|
3828
|
cp = CP_SW; |
|
3829
|
}else{ |
|
3830
|
cp = CP_S; |
|
3831
|
} |
|
3832
|
} |
|
3833
|
chop = pObj->type->xOffset(p,pObj,cp); |
|
3834
|
chop.x += pObj->ptAt.x; |
|
3835
|
chop.y += pObj->ptAt.y; |
|
3836
|
return chop; |
|
3837
|
} |
|
3838
|
static void boxFit(Pik *p, PObj *pObj, PNum w, PNum h){ |
|
3839
|
if( w>0 ) pObj->w = w; |
|
3840
|
if( h>0 ) pObj->h = h; |
|
3841
|
UNUSED_PARAMETER(p); |
|
3842
|
} |
|
3843
|
static void boxRender(Pik *p, PObj *pObj){ |
|
3844
|
PNum w2 = 0.5*pObj->w; |
|
3845
|
PNum h2 = 0.5*pObj->h; |
|
3846
|
PNum rad = pObj->rad; |
|
3847
|
PPoint pt = pObj->ptAt; |
|
3848
|
if( pObj->sw>=0.0 ){ |
|
3849
|
if( rad<=0.0 ){ |
|
3850
|
pik_append_xy(p,"<path d=\"M", pt.x-w2,pt.y-h2); |
|
3851
|
pik_append_xy(p,"L", pt.x+w2,pt.y-h2); |
|
3852
|
pik_append_xy(p,"L", pt.x+w2,pt.y+h2); |
|
3853
|
pik_append_xy(p,"L", pt.x-w2,pt.y+h2); |
|
3854
|
pik_append(p,"Z\" ",-1); |
|
3855
|
}else{ |
|
3856
|
/* |
|
3857
|
** ---- - y3 |
|
3858
|
** / \ |
|
3859
|
** / \ _ y2 |
|
3860
|
** | | |
|
3861
|
** | | _ y1 |
|
3862
|
** \ / |
|
3863
|
** \ / |
|
3864
|
** ---- _ y0 |
|
3865
|
** |
|
3866
|
** ' ' ' ' |
|
3867
|
** x0 x1 x2 x3 |
|
3868
|
*/ |
|
3869
|
PNum x0,x1,x2,x3,y0,y1,y2,y3; |
|
3870
|
if( rad>w2 ) rad = w2; |
|
3871
|
if( rad>h2 ) rad = h2; |
|
3872
|
x0 = pt.x - w2; |
|
3873
|
x1 = x0 + rad; |
|
3874
|
x3 = pt.x + w2; |
|
3875
|
x2 = x3 - rad; |
|
3876
|
y0 = pt.y - h2; |
|
3877
|
y1 = y0 + rad; |
|
3878
|
y3 = pt.y + h2; |
|
3879
|
y2 = y3 - rad; |
|
3880
|
pik_append_xy(p,"<path d=\"M", x1, y0); |
|
3881
|
if( x2>x1 ) pik_append_xy(p, "L", x2, y0); |
|
3882
|
pik_append_arc(p, rad, rad, x3, y1); |
|
3883
|
if( y2>y1 ) pik_append_xy(p, "L", x3, y2); |
|
3884
|
pik_append_arc(p, rad, rad, x2, y3); |
|
3885
|
if( x2>x1 ) pik_append_xy(p, "L", x1, y3); |
|
3886
|
pik_append_arc(p, rad, rad, x0, y2); |
|
3887
|
if( y2>y1 ) pik_append_xy(p, "L", x0, y1); |
|
3888
|
pik_append_arc(p, rad, rad, x1, y0); |
|
3889
|
pik_append(p,"Z\" ",-1); |
|
3890
|
} |
|
3891
|
pik_append_style(p,pObj,3); |
|
3892
|
pik_append(p,"\" />\n", -1); |
|
3893
|
} |
|
3894
|
pik_append_txt(p, pObj, 0); |
|
3895
|
} |
|
3896
|
|
|
3897
|
/* Methods for the "circle" class */ |
|
3898
|
static void circleInit(Pik *p, PObj *pObj){ |
|
3899
|
pObj->w = pik_value(p, "circlerad",9,0)*2; |
|
3900
|
pObj->h = pObj->w; |
|
3901
|
pObj->rad = 0.5*pObj->w; |
|
3902
|
} |
|
3903
|
static void circleNumProp(Pik *p, PObj *pObj, PToken *pId){ |
|
3904
|
/* For a circle, the width must equal the height and both must |
|
3905
|
** be twice the radius. Enforce those constraints. */ |
|
3906
|
switch( pId->eType ){ |
|
3907
|
case T_DIAMETER: |
|
3908
|
case T_RADIUS: |
|
3909
|
pObj->w = pObj->h = 2.0*pObj->rad; |
|
3910
|
break; |
|
3911
|
case T_WIDTH: |
|
3912
|
pObj->h = pObj->w; |
|
3913
|
pObj->rad = 0.5*pObj->w; |
|
3914
|
break; |
|
3915
|
case T_HEIGHT: |
|
3916
|
pObj->w = pObj->h; |
|
3917
|
pObj->rad = 0.5*pObj->w; |
|
3918
|
break; |
|
3919
|
} |
|
3920
|
UNUSED_PARAMETER(p); |
|
3921
|
} |
|
3922
|
static PPoint circleChop(Pik *p, PObj *pObj, PPoint *pPt){ |
|
3923
|
PPoint chop; |
|
3924
|
PNum dx = pPt->x - pObj->ptAt.x; |
|
3925
|
PNum dy = pPt->y - pObj->ptAt.y; |
|
3926
|
PNum dist = hypot(dx,dy); |
|
3927
|
if( dist<pObj->rad || dist<=0 ) return pObj->ptAt; |
|
3928
|
chop.x = pObj->ptAt.x + dx*pObj->rad/dist; |
|
3929
|
chop.y = pObj->ptAt.y + dy*pObj->rad/dist; |
|
3930
|
UNUSED_PARAMETER(p); |
|
3931
|
return chop; |
|
3932
|
} |
|
3933
|
static void circleFit(Pik *p, PObj *pObj, PNum w, PNum h){ |
|
3934
|
PNum mx = 0.0; |
|
3935
|
if( w>0 ) mx = w; |
|
3936
|
if( h>mx ) mx = h; |
|
3937
|
if( w*h>0 && (w*w + h*h) > mx*mx ){ |
|
3938
|
mx = hypot(w,h); |
|
3939
|
} |
|
3940
|
if( mx>0.0 ){ |
|
3941
|
pObj->rad = 0.5*mx; |
|
3942
|
pObj->w = pObj->h = mx; |
|
3943
|
} |
|
3944
|
UNUSED_PARAMETER(p); |
|
3945
|
} |
|
3946
|
|
|
3947
|
static void circleRender(Pik *p, PObj *pObj){ |
|
3948
|
PNum r = pObj->rad; |
|
3949
|
PPoint pt = pObj->ptAt; |
|
3950
|
if( pObj->sw>=0.0 ){ |
|
3951
|
pik_append_x(p,"<circle cx=\"", pt.x, "\""); |
|
3952
|
pik_append_y(p," cy=\"", pt.y, "\""); |
|
3953
|
pik_append_dis(p," r=\"", r, "\" "); |
|
3954
|
pik_append_style(p,pObj,3); |
|
3955
|
pik_append(p,"\" />\n", -1); |
|
3956
|
} |
|
3957
|
pik_append_txt(p, pObj, 0); |
|
3958
|
} |
|
3959
|
|
|
3960
|
/* Methods for the "cylinder" class */ |
|
3961
|
static void cylinderInit(Pik *p, PObj *pObj){ |
|
3962
|
pObj->w = pik_value(p, "cylwid",6,0); |
|
3963
|
pObj->h = pik_value(p, "cylht",5,0); |
|
3964
|
pObj->rad = pik_value(p, "cylrad",6,0); /* Minor radius of ellipses */ |
|
3965
|
} |
|
3966
|
static void cylinderFit(Pik *p, PObj *pObj, PNum w, PNum h){ |
|
3967
|
if( w>0 ) pObj->w = w; |
|
3968
|
if( h>0 ) pObj->h = h + 0.25*pObj->rad + pObj->sw; |
|
3969
|
UNUSED_PARAMETER(p); |
|
3970
|
} |
|
3971
|
static void cylinderRender(Pik *p, PObj *pObj){ |
|
3972
|
PNum w2 = 0.5*pObj->w; |
|
3973
|
PNum h2 = 0.5*pObj->h; |
|
3974
|
PNum rad = pObj->rad; |
|
3975
|
PPoint pt = pObj->ptAt; |
|
3976
|
if( pObj->sw>=0.0 ){ |
|
3977
|
if( rad>h2 ){ |
|
3978
|
rad = h2; |
|
3979
|
}else if( rad<0 ){ |
|
3980
|
rad = 0; |
|
3981
|
} |
|
3982
|
pik_append_xy(p,"<path d=\"M", pt.x-w2,pt.y+h2-rad); |
|
3983
|
pik_append_xy(p,"L", pt.x-w2,pt.y-h2+rad); |
|
3984
|
pik_append_arc(p,w2,rad,pt.x+w2,pt.y-h2+rad); |
|
3985
|
pik_append_xy(p,"L", pt.x+w2,pt.y+h2-rad); |
|
3986
|
pik_append_arc(p,w2,rad,pt.x-w2,pt.y+h2-rad); |
|
3987
|
pik_append_arc(p,w2,rad,pt.x+w2,pt.y+h2-rad); |
|
3988
|
pik_append(p,"\" ",-1); |
|
3989
|
pik_append_style(p,pObj,3); |
|
3990
|
pik_append(p,"\" />\n", -1); |
|
3991
|
} |
|
3992
|
pik_append_txt(p, pObj, 0); |
|
3993
|
} |
|
3994
|
static PPoint cylinderOffset(Pik *p, PObj *pObj, int cp){ |
|
3995
|
PPoint pt = cZeroPoint; |
|
3996
|
PNum w2 = pObj->w*0.5; |
|
3997
|
PNum h1 = pObj->h*0.5; |
|
3998
|
PNum h2 = h1 - pObj->rad; |
|
3999
|
switch( cp ){ |
|
4000
|
case CP_C: break; |
|
4001
|
case CP_N: pt.x = 0.0; pt.y = h1; break; |
|
4002
|
case CP_NE: pt.x = w2; pt.y = h2; break; |
|
4003
|
case CP_E: pt.x = w2; pt.y = 0.0; break; |
|
4004
|
case CP_SE: pt.x = w2; pt.y = -h2; break; |
|
4005
|
case CP_S: pt.x = 0.0; pt.y = -h1; break; |
|
4006
|
case CP_SW: pt.x = -w2; pt.y = -h2; break; |
|
4007
|
case CP_W: pt.x = -w2; pt.y = 0.0; break; |
|
4008
|
case CP_NW: pt.x = -w2; pt.y = h2; break; |
|
4009
|
default: assert(0); |
|
4010
|
} |
|
4011
|
UNUSED_PARAMETER(p); |
|
4012
|
return pt; |
|
4013
|
} |
|
4014
|
|
|
4015
|
/* Methods for the "dot" class */ |
|
4016
|
static void dotInit(Pik *p, PObj *pObj){ |
|
4017
|
pObj->rad = pik_value(p, "dotrad",6,0); |
|
4018
|
pObj->h = pObj->w = pObj->rad*6; |
|
4019
|
pObj->fill = pObj->color; |
|
4020
|
} |
|
4021
|
static void dotNumProp(Pik *p, PObj *pObj, PToken *pId){ |
|
4022
|
switch( pId->eType ){ |
|
4023
|
case T_COLOR: |
|
4024
|
pObj->fill = pObj->color; |
|
4025
|
break; |
|
4026
|
case T_FILL: |
|
4027
|
pObj->color = pObj->fill; |
|
4028
|
break; |
|
4029
|
} |
|
4030
|
UNUSED_PARAMETER(p); |
|
4031
|
} |
|
4032
|
static void dotCheck(Pik *p, PObj *pObj){ |
|
4033
|
pObj->w = pObj->h = 0; |
|
4034
|
pik_bbox_addellipse(&pObj->bbox, pObj->ptAt.x, pObj->ptAt.y, |
|
4035
|
pObj->rad, pObj->rad); |
|
4036
|
UNUSED_PARAMETER(p); |
|
4037
|
} |
|
4038
|
static PPoint dotOffset(Pik *p, PObj *pObj, int cp){ |
|
4039
|
UNUSED_PARAMETER(p); |
|
4040
|
UNUSED_PARAMETER(pObj); |
|
4041
|
UNUSED_PARAMETER(cp); |
|
4042
|
return cZeroPoint; |
|
4043
|
} |
|
4044
|
static void dotRender(Pik *p, PObj *pObj){ |
|
4045
|
PNum r = pObj->rad; |
|
4046
|
PPoint pt = pObj->ptAt; |
|
4047
|
if( pObj->sw>=0.0 ){ |
|
4048
|
pik_append_x(p,"<circle cx=\"", pt.x, "\""); |
|
4049
|
pik_append_y(p," cy=\"", pt.y, "\""); |
|
4050
|
pik_append_dis(p," r=\"", r, "\""); |
|
4051
|
pik_append_style(p,pObj,2); |
|
4052
|
pik_append(p,"\" />\n", -1); |
|
4053
|
} |
|
4054
|
pik_append_txt(p, pObj, 0); |
|
4055
|
} |
|
4056
|
|
|
4057
|
/* Methods for the "diamond" class */ |
|
4058
|
static void diamondInit(Pik *p, PObj *pObj){ |
|
4059
|
pObj->w = pik_value(p, "diamondwid",10,0); |
|
4060
|
pObj->h = pik_value(p, "diamondht",9,0); |
|
4061
|
pObj->bAltAutoFit = 1; |
|
4062
|
} |
|
4063
|
/* Return offset from the center of the box to the compass point |
|
4064
|
** given by parameter cp */ |
|
4065
|
static PPoint diamondOffset(Pik *p, PObj *pObj, int cp){ |
|
4066
|
PPoint pt = cZeroPoint; |
|
4067
|
PNum w2 = 0.5*pObj->w; |
|
4068
|
PNum w4 = 0.25*pObj->w; |
|
4069
|
PNum h2 = 0.5*pObj->h; |
|
4070
|
PNum h4 = 0.25*pObj->h; |
|
4071
|
switch( cp ){ |
|
4072
|
case CP_C: break; |
|
4073
|
case CP_N: pt.x = 0.0; pt.y = h2; break; |
|
4074
|
case CP_NE: pt.x = w4; pt.y = h4; break; |
|
4075
|
case CP_E: pt.x = w2; pt.y = 0.0; break; |
|
4076
|
case CP_SE: pt.x = w4; pt.y = -h4; break; |
|
4077
|
case CP_S: pt.x = 0.0; pt.y = -h2; break; |
|
4078
|
case CP_SW: pt.x = -w4; pt.y = -h4; break; |
|
4079
|
case CP_W: pt.x = -w2; pt.y = 0.0; break; |
|
4080
|
case CP_NW: pt.x = -w4; pt.y = h4; break; |
|
4081
|
default: assert(0); |
|
4082
|
} |
|
4083
|
UNUSED_PARAMETER(p); |
|
4084
|
return pt; |
|
4085
|
} |
|
4086
|
static void diamondFit(Pik *p, PObj *pObj, PNum w, PNum h){ |
|
4087
|
if( pObj->w<=0 ) pObj->w = w*1.5; |
|
4088
|
if( pObj->h<=0 ) pObj->h = h*1.5; |
|
4089
|
if( pObj->w>0 && pObj->h>0 ){ |
|
4090
|
PNum x = pObj->w*h/pObj->h + w; |
|
4091
|
PNum y = pObj->h*x/pObj->w; |
|
4092
|
pObj->w = x; |
|
4093
|
pObj->h = y; |
|
4094
|
} |
|
4095
|
UNUSED_PARAMETER(p); |
|
4096
|
} |
|
4097
|
static void diamondRender(Pik *p, PObj *pObj){ |
|
4098
|
PNum w2 = 0.5*pObj->w; |
|
4099
|
PNum h2 = 0.5*pObj->h; |
|
4100
|
PPoint pt = pObj->ptAt; |
|
4101
|
if( pObj->sw>=0.0 ){ |
|
4102
|
pik_append_xy(p,"<path d=\"M", pt.x-w2,pt.y); |
|
4103
|
pik_append_xy(p,"L", pt.x,pt.y-h2); |
|
4104
|
pik_append_xy(p,"L", pt.x+w2,pt.y); |
|
4105
|
pik_append_xy(p,"L", pt.x,pt.y+h2); |
|
4106
|
pik_append(p,"Z\" ",-1); |
|
4107
|
pik_append_style(p,pObj,3); |
|
4108
|
pik_append(p,"\" />\n", -1); |
|
4109
|
} |
|
4110
|
pik_append_txt(p, pObj, 0); |
|
4111
|
} |
|
4112
|
|
|
4113
|
|
|
4114
|
/* Methods for the "ellipse" class */ |
|
4115
|
static void ellipseInit(Pik *p, PObj *pObj){ |
|
4116
|
pObj->w = pik_value(p, "ellipsewid",10,0); |
|
4117
|
pObj->h = pik_value(p, "ellipseht",9,0); |
|
4118
|
} |
|
4119
|
static PPoint ellipseChop(Pik *p, PObj *pObj, PPoint *pPt){ |
|
4120
|
PPoint chop; |
|
4121
|
PNum s, dq, dist; |
|
4122
|
PNum dx = pPt->x - pObj->ptAt.x; |
|
4123
|
PNum dy = pPt->y - pObj->ptAt.y; |
|
4124
|
if( pObj->w<=0.0 ) return pObj->ptAt; |
|
4125
|
if( pObj->h<=0.0 ) return pObj->ptAt; |
|
4126
|
s = pObj->h/pObj->w; |
|
4127
|
dq = dx*s; |
|
4128
|
dist = hypot(dq,dy); |
|
4129
|
if( dist<pObj->h ) return pObj->ptAt; |
|
4130
|
chop.x = pObj->ptAt.x + 0.5*dq*pObj->h/(dist*s); |
|
4131
|
chop.y = pObj->ptAt.y + 0.5*dy*pObj->h/dist; |
|
4132
|
UNUSED_PARAMETER(p); |
|
4133
|
return chop; |
|
4134
|
} |
|
4135
|
static PPoint ellipseOffset(Pik *p, PObj *pObj, int cp){ |
|
4136
|
PPoint pt = cZeroPoint; |
|
4137
|
PNum w = pObj->w*0.5; |
|
4138
|
PNum w2 = w*0.70710678118654747608; |
|
4139
|
PNum h = pObj->h*0.5; |
|
4140
|
PNum h2 = h*0.70710678118654747608; |
|
4141
|
switch( cp ){ |
|
4142
|
case CP_C: break; |
|
4143
|
case CP_N: pt.x = 0.0; pt.y = h; break; |
|
4144
|
case CP_NE: pt.x = w2; pt.y = h2; break; |
|
4145
|
case CP_E: pt.x = w; pt.y = 0.0; break; |
|
4146
|
case CP_SE: pt.x = w2; pt.y = -h2; break; |
|
4147
|
case CP_S: pt.x = 0.0; pt.y = -h; break; |
|
4148
|
case CP_SW: pt.x = -w2; pt.y = -h2; break; |
|
4149
|
case CP_W: pt.x = -w; pt.y = 0.0; break; |
|
4150
|
case CP_NW: pt.x = -w2; pt.y = h2; break; |
|
4151
|
default: assert(0); |
|
4152
|
} |
|
4153
|
UNUSED_PARAMETER(p); |
|
4154
|
return pt; |
|
4155
|
} |
|
4156
|
static void ellipseRender(Pik *p, PObj *pObj){ |
|
4157
|
PNum w = pObj->w; |
|
4158
|
PNum h = pObj->h; |
|
4159
|
PPoint pt = pObj->ptAt; |
|
4160
|
if( pObj->sw>=0.0 ){ |
|
4161
|
pik_append_x(p,"<ellipse cx=\"", pt.x, "\""); |
|
4162
|
pik_append_y(p," cy=\"", pt.y, "\""); |
|
4163
|
pik_append_dis(p," rx=\"", w/2.0, "\""); |
|
4164
|
pik_append_dis(p," ry=\"", h/2.0, "\" "); |
|
4165
|
pik_append_style(p,pObj,3); |
|
4166
|
pik_append(p,"\" />\n", -1); |
|
4167
|
} |
|
4168
|
pik_append_txt(p, pObj, 0); |
|
4169
|
} |
|
4170
|
|
|
4171
|
/* Methods for the "file" object */ |
|
4172
|
static void fileInit(Pik *p, PObj *pObj){ |
|
4173
|
pObj->w = pik_value(p, "filewid",7,0); |
|
4174
|
pObj->h = pik_value(p, "fileht",6,0); |
|
4175
|
pObj->rad = pik_value(p, "filerad",7,0); |
|
4176
|
} |
|
4177
|
/* Return offset from the center of the file to the compass point |
|
4178
|
** given by parameter cp */ |
|
4179
|
static PPoint fileOffset(Pik *p, PObj *pObj, int cp){ |
|
4180
|
PPoint pt = cZeroPoint; |
|
4181
|
PNum w2 = 0.5*pObj->w; |
|
4182
|
PNum h2 = 0.5*pObj->h; |
|
4183
|
PNum rx = pObj->rad; |
|
4184
|
PNum mn = w2<h2 ? w2 : h2; |
|
4185
|
if( rx>mn ) rx = mn; |
|
4186
|
if( rx<mn*0.25 ) rx = mn*0.25; |
|
4187
|
pt.x = pt.y = 0.0; |
|
4188
|
rx *= 0.5; |
|
4189
|
switch( cp ){ |
|
4190
|
case CP_C: break; |
|
4191
|
case CP_N: pt.x = 0.0; pt.y = h2; break; |
|
4192
|
case CP_NE: pt.x = w2-rx; pt.y = h2-rx; break; |
|
4193
|
case CP_E: pt.x = w2; pt.y = 0.0; break; |
|
4194
|
case CP_SE: pt.x = w2; pt.y = -h2; break; |
|
4195
|
case CP_S: pt.x = 0.0; pt.y = -h2; break; |
|
4196
|
case CP_SW: pt.x = -w2; pt.y = -h2; break; |
|
4197
|
case CP_W: pt.x = -w2; pt.y = 0.0; break; |
|
4198
|
case CP_NW: pt.x = -w2; pt.y = h2; break; |
|
4199
|
default: assert(0); |
|
4200
|
} |
|
4201
|
UNUSED_PARAMETER(p); |
|
4202
|
return pt; |
|
4203
|
} |
|
4204
|
static void fileFit(Pik *p, PObj *pObj, PNum w, PNum h){ |
|
4205
|
if( w>0 ) pObj->w = w; |
|
4206
|
if( h>0 ) pObj->h = h + 2*pObj->rad; |
|
4207
|
UNUSED_PARAMETER(p); |
|
4208
|
} |
|
4209
|
static void fileRender(Pik *p, PObj *pObj){ |
|
4210
|
PNum w2 = 0.5*pObj->w; |
|
4211
|
PNum h2 = 0.5*pObj->h; |
|
4212
|
PNum rad = pObj->rad; |
|
4213
|
PPoint pt = pObj->ptAt; |
|
4214
|
PNum mn = w2<h2 ? w2 : h2; |
|
4215
|
if( rad>mn ) rad = mn; |
|
4216
|
if( rad<mn*0.25 ) rad = mn*0.25; |
|
4217
|
if( pObj->sw>=0.0 ){ |
|
4218
|
pik_append_xy(p,"<path d=\"M", pt.x-w2,pt.y-h2); |
|
4219
|
pik_append_xy(p,"L", pt.x+w2,pt.y-h2); |
|
4220
|
pik_append_xy(p,"L", pt.x+w2,pt.y+(h2-rad)); |
|
4221
|
pik_append_xy(p,"L", pt.x+(w2-rad),pt.y+h2); |
|
4222
|
pik_append_xy(p,"L", pt.x-w2,pt.y+h2); |
|
4223
|
pik_append(p,"Z\" ",-1); |
|
4224
|
pik_append_style(p,pObj,1); |
|
4225
|
pik_append(p,"\" />\n",-1); |
|
4226
|
pik_append_xy(p,"<path d=\"M", pt.x+(w2-rad), pt.y+h2); |
|
4227
|
pik_append_xy(p,"L", pt.x+(w2-rad),pt.y+(h2-rad)); |
|
4228
|
pik_append_xy(p,"L", pt.x+w2, pt.y+(h2-rad)); |
|
4229
|
pik_append(p,"\" ",-1); |
|
4230
|
pik_append_style(p,pObj,0); |
|
4231
|
pik_append(p,"\" />\n",-1); |
|
4232
|
} |
|
4233
|
pik_append_txt(p, pObj, 0); |
|
4234
|
} |
|
4235
|
|
|
4236
|
|
|
4237
|
/* Methods for the "line" class */ |
|
4238
|
static void lineInit(Pik *p, PObj *pObj){ |
|
4239
|
pObj->w = pik_value(p, "linewid",7,0); |
|
4240
|
pObj->h = pik_value(p, "lineht",6,0); |
|
4241
|
pObj->rad = pik_value(p, "linerad",7,0); |
|
4242
|
} |
|
4243
|
static PPoint lineOffset(Pik *p, PObj *pObj, int cp){ |
|
4244
|
#if 0 |
|
4245
|
/* In legacy PIC, the .center of an unclosed line is half way between |
|
4246
|
** its .start and .end. */ |
|
4247
|
if( cp==CP_C && !pObj->bClose ){ |
|
4248
|
PPoint out; |
|
4249
|
out.x = 0.5*(pObj->ptEnter.x + pObj->ptExit.x) - pObj->ptAt.x; |
|
4250
|
out.y = 0.5*(pObj->ptEnter.x + pObj->ptExit.y) - pObj->ptAt.y; |
|
4251
|
return out; |
|
4252
|
} |
|
4253
|
#endif |
|
4254
|
return boxOffset(p,pObj,cp); |
|
4255
|
} |
|
4256
|
static void lineRender(Pik *p, PObj *pObj){ |
|
4257
|
int i; |
|
4258
|
if( pObj->sw>0.0 ){ |
|
4259
|
const char *z = "<path d=\"M"; |
|
4260
|
int n = pObj->nPath; |
|
4261
|
if( pObj->larrow ){ |
|
4262
|
pik_draw_arrowhead(p,&pObj->aPath[1],&pObj->aPath[0],pObj); |
|
4263
|
} |
|
4264
|
if( pObj->rarrow ){ |
|
4265
|
pik_draw_arrowhead(p,&pObj->aPath[n-2],&pObj->aPath[n-1],pObj); |
|
4266
|
} |
|
4267
|
for(i=0; i<pObj->nPath; i++){ |
|
4268
|
pik_append_xy(p,z,pObj->aPath[i].x,pObj->aPath[i].y); |
|
4269
|
z = "L"; |
|
4270
|
} |
|
4271
|
if( pObj->bClose ){ |
|
4272
|
pik_append(p,"Z",1); |
|
4273
|
}else{ |
|
4274
|
pObj->fill = -1.0; |
|
4275
|
} |
|
4276
|
pik_append(p,"\" ",-1); |
|
4277
|
pik_append_style(p,pObj,pObj->bClose?3:0); |
|
4278
|
pik_append(p,"\" />\n", -1); |
|
4279
|
} |
|
4280
|
pik_append_txt(p, pObj, 0); |
|
4281
|
} |
|
4282
|
|
|
4283
|
/* Methods for the "move" class */ |
|
4284
|
static void moveInit(Pik *p, PObj *pObj){ |
|
4285
|
pObj->w = pik_value(p, "movewid",7,0); |
|
4286
|
pObj->h = pObj->w; |
|
4287
|
pObj->fill = -1.0; |
|
4288
|
pObj->color = -1.0; |
|
4289
|
pObj->sw = -1.0; |
|
4290
|
} |
|
4291
|
static void moveRender(Pik *p, PObj *pObj){ |
|
4292
|
/* No-op */ |
|
4293
|
UNUSED_PARAMETER(p); |
|
4294
|
UNUSED_PARAMETER(pObj); |
|
4295
|
} |
|
4296
|
|
|
4297
|
/* Methods for the "oval" class */ |
|
4298
|
static void ovalInit(Pik *p, PObj *pObj){ |
|
4299
|
pObj->h = pik_value(p, "ovalht",6,0); |
|
4300
|
pObj->w = pik_value(p, "ovalwid",7,0); |
|
4301
|
pObj->rad = 0.5*(pObj->h<pObj->w?pObj->h:pObj->w); |
|
4302
|
} |
|
4303
|
static void ovalNumProp(Pik *p, PObj *pObj, PToken *pId){ |
|
4304
|
UNUSED_PARAMETER(p); |
|
4305
|
UNUSED_PARAMETER(pId); |
|
4306
|
/* Always adjust the radius to be half of the smaller of |
|
4307
|
** the width and height. */ |
|
4308
|
pObj->rad = 0.5*(pObj->h<pObj->w?pObj->h:pObj->w); |
|
4309
|
} |
|
4310
|
static void ovalFit(Pik *p, PObj *pObj, PNum w, PNum h){ |
|
4311
|
UNUSED_PARAMETER(p); |
|
4312
|
if( w>0 ) pObj->w = w; |
|
4313
|
if( h>0 ) pObj->h = h; |
|
4314
|
if( pObj->w<pObj->h ) pObj->w = pObj->h; |
|
4315
|
pObj->rad = 0.5*(pObj->h<pObj->w?pObj->h:pObj->w); |
|
4316
|
} |
|
4317
|
|
|
4318
|
|
|
4319
|
|
|
4320
|
/* Methods for the "spline" class */ |
|
4321
|
static void splineInit(Pik *p, PObj *pObj){ |
|
4322
|
pObj->w = pik_value(p, "linewid",7,0); |
|
4323
|
pObj->h = pik_value(p, "lineht",6,0); |
|
4324
|
pObj->rad = 1000; |
|
4325
|
} |
|
4326
|
/* Return a point along the path from "f" to "t" that is r units |
|
4327
|
** prior to reaching "t", except if the path is less than 2*r total, |
|
4328
|
** return the midpoint. |
|
4329
|
*/ |
|
4330
|
static PPoint radiusMidpoint(PPoint f, PPoint t, PNum r, int *pbMid){ |
|
4331
|
PNum dx = t.x - f.x; |
|
4332
|
PNum dy = t.y - f.y; |
|
4333
|
PNum dist = hypot(dx,dy); |
|
4334
|
PPoint m; |
|
4335
|
if( dist<=0.0 ) return t; |
|
4336
|
dx /= dist; |
|
4337
|
dy /= dist; |
|
4338
|
if( r > 0.5*dist ){ |
|
4339
|
r = 0.5*dist; |
|
4340
|
*pbMid = 1; |
|
4341
|
}else{ |
|
4342
|
*pbMid = 0; |
|
4343
|
} |
|
4344
|
m.x = t.x - r*dx; |
|
4345
|
m.y = t.y - r*dy; |
|
4346
|
return m; |
|
4347
|
} |
|
4348
|
static void radiusPath(Pik *p, PObj *pObj, PNum r){ |
|
4349
|
int i; |
|
4350
|
int n = pObj->nPath; |
|
4351
|
const PPoint *a = pObj->aPath; |
|
4352
|
PPoint m; |
|
4353
|
PPoint an = a[n-1]; |
|
4354
|
int isMid = 0; |
|
4355
|
int iLast = pObj->bClose ? n : n-1; |
|
4356
|
|
|
4357
|
pik_append_xy(p,"<path d=\"M", a[0].x, a[0].y); |
|
4358
|
m = radiusMidpoint(a[0], a[1], r, &isMid); |
|
4359
|
pik_append_xy(p," L ",m.x,m.y); |
|
4360
|
for(i=1; i<iLast; i++){ |
|
4361
|
an = i<n-1 ? a[i+1] : a[0]; |
|
4362
|
m = radiusMidpoint(an,a[i],r, &isMid); |
|
4363
|
pik_append_xy(p," Q ",a[i].x,a[i].y); |
|
4364
|
pik_append_xy(p," ",m.x,m.y); |
|
4365
|
if( !isMid ){ |
|
4366
|
m = radiusMidpoint(a[i],an,r, &isMid); |
|
4367
|
pik_append_xy(p," L ",m.x,m.y); |
|
4368
|
} |
|
4369
|
} |
|
4370
|
pik_append_xy(p," L ",an.x,an.y); |
|
4371
|
if( pObj->bClose ){ |
|
4372
|
pik_append(p,"Z",1); |
|
4373
|
}else{ |
|
4374
|
pObj->fill = -1.0; |
|
4375
|
} |
|
4376
|
pik_append(p,"\" ",-1); |
|
4377
|
pik_append_style(p,pObj,pObj->bClose?3:0); |
|
4378
|
pik_append(p,"\" />\n", -1); |
|
4379
|
} |
|
4380
|
static void splineRender(Pik *p, PObj *pObj){ |
|
4381
|
if( pObj->sw>0.0 ){ |
|
4382
|
int n = pObj->nPath; |
|
4383
|
PNum r = pObj->rad; |
|
4384
|
if( n<3 || r<=0.0 ){ |
|
4385
|
lineRender(p,pObj); |
|
4386
|
return; |
|
4387
|
} |
|
4388
|
if( pObj->larrow ){ |
|
4389
|
pik_draw_arrowhead(p,&pObj->aPath[1],&pObj->aPath[0],pObj); |
|
4390
|
} |
|
4391
|
if( pObj->rarrow ){ |
|
4392
|
pik_draw_arrowhead(p,&pObj->aPath[n-2],&pObj->aPath[n-1],pObj); |
|
4393
|
} |
|
4394
|
radiusPath(p,pObj,pObj->rad); |
|
4395
|
} |
|
4396
|
pik_append_txt(p, pObj, 0); |
|
4397
|
} |
|
4398
|
|
|
4399
|
|
|
4400
|
/* Methods for the "text" class */ |
|
4401
|
static void textInit(Pik *p, PObj *pObj){ |
|
4402
|
pik_value(p, "textwid",7,0); |
|
4403
|
pik_value(p, "textht",6,0); |
|
4404
|
pObj->sw = 0.0; |
|
4405
|
} |
|
4406
|
static PPoint textOffset(Pik *p, PObj *pObj, int cp){ |
|
4407
|
/* Automatically slim-down the width and height of text |
|
4408
|
** statements so that the bounding box tightly encloses the text, |
|
4409
|
** then get boxOffset() to do the offset computation. |
|
4410
|
*/ |
|
4411
|
pik_size_to_fit(p, pObj, &pObj->errTok,3); |
|
4412
|
return boxOffset(p, pObj, cp); |
|
4413
|
} |
|
4414
|
static void textRender(Pik *p, PObj *pObj){ |
|
4415
|
pik_append_txt(p, pObj, 0); |
|
4416
|
} |
|
4417
|
|
|
4418
|
|
|
4419
|
/* Methods for the "sublist" class */ |
|
4420
|
static void sublistInit(Pik *p, PObj *pObj){ |
|
4421
|
PList *pList = pObj->pSublist; |
|
4422
|
int i; |
|
4423
|
UNUSED_PARAMETER(p); |
|
4424
|
pik_bbox_init(&pObj->bbox); |
|
4425
|
for(i=0; i<pList->n; i++){ |
|
4426
|
pik_bbox_addbox(&pObj->bbox, &pList->a[i]->bbox); |
|
4427
|
} |
|
4428
|
pObj->w = pObj->bbox.ne.x - pObj->bbox.sw.x; |
|
4429
|
pObj->h = pObj->bbox.ne.y - pObj->bbox.sw.y; |
|
4430
|
pObj->ptAt.x = 0.5*(pObj->bbox.ne.x + pObj->bbox.sw.x); |
|
4431
|
pObj->ptAt.y = 0.5*(pObj->bbox.ne.y + pObj->bbox.sw.y); |
|
4432
|
pObj->mCalc |= A_WIDTH|A_HEIGHT|A_RADIUS; |
|
4433
|
} |
|
4434
|
|
|
4435
|
|
|
4436
|
/* |
|
4437
|
** The following array holds all the different kinds of objects. |
|
4438
|
** The special [] object is separate. |
|
4439
|
*/ |
|
4440
|
static const PClass aClass[] = { |
|
4441
|
{ /* name */ "arc", |
|
4442
|
/* isline */ 1, |
|
4443
|
/* eJust */ 0, |
|
4444
|
/* xInit */ arcInit, |
|
4445
|
/* xNumProp */ 0, |
|
4446
|
/* xCheck */ arcCheck, |
|
4447
|
/* xChop */ 0, |
|
4448
|
/* xOffset */ boxOffset, |
|
4449
|
/* xFit */ 0, |
|
4450
|
/* xRender */ arcRender |
|
4451
|
}, |
|
4452
|
{ /* name */ "arrow", |
|
4453
|
/* isline */ 1, |
|
4454
|
/* eJust */ 0, |
|
4455
|
/* xInit */ arrowInit, |
|
4456
|
/* xNumProp */ 0, |
|
4457
|
/* xCheck */ 0, |
|
4458
|
/* xChop */ 0, |
|
4459
|
/* xOffset */ lineOffset, |
|
4460
|
/* xFit */ 0, |
|
4461
|
/* xRender */ splineRender |
|
4462
|
}, |
|
4463
|
{ /* name */ "box", |
|
4464
|
/* isline */ 0, |
|
4465
|
/* eJust */ 1, |
|
4466
|
/* xInit */ boxInit, |
|
4467
|
/* xNumProp */ 0, |
|
4468
|
/* xCheck */ 0, |
|
4469
|
/* xChop */ boxChop, |
|
4470
|
/* xOffset */ boxOffset, |
|
4471
|
/* xFit */ boxFit, |
|
4472
|
/* xRender */ boxRender |
|
4473
|
}, |
|
4474
|
{ /* name */ "circle", |
|
4475
|
/* isline */ 0, |
|
4476
|
/* eJust */ 0, |
|
4477
|
/* xInit */ circleInit, |
|
4478
|
/* xNumProp */ circleNumProp, |
|
4479
|
/* xCheck */ 0, |
|
4480
|
/* xChop */ circleChop, |
|
4481
|
/* xOffset */ ellipseOffset, |
|
4482
|
/* xFit */ circleFit, |
|
4483
|
/* xRender */ circleRender |
|
4484
|
}, |
|
4485
|
{ /* name */ "cylinder", |
|
4486
|
/* isline */ 0, |
|
4487
|
/* eJust */ 1, |
|
4488
|
/* xInit */ cylinderInit, |
|
4489
|
/* xNumProp */ 0, |
|
4490
|
/* xCheck */ 0, |
|
4491
|
/* xChop */ boxChop, |
|
4492
|
/* xOffset */ cylinderOffset, |
|
4493
|
/* xFit */ cylinderFit, |
|
4494
|
/* xRender */ cylinderRender |
|
4495
|
}, |
|
4496
|
{ /* name */ "diamond", |
|
4497
|
/* isline */ 0, |
|
4498
|
/* eJust */ 0, |
|
4499
|
/* xInit */ diamondInit, |
|
4500
|
/* xNumProp */ 0, |
|
4501
|
/* xCheck */ 0, |
|
4502
|
/* xChop */ boxChop, |
|
4503
|
/* xOffset */ diamondOffset, |
|
4504
|
/* xFit */ diamondFit, |
|
4505
|
/* xRender */ diamondRender |
|
4506
|
}, |
|
4507
|
{ /* name */ "dot", |
|
4508
|
/* isline */ 0, |
|
4509
|
/* eJust */ 0, |
|
4510
|
/* xInit */ dotInit, |
|
4511
|
/* xNumProp */ dotNumProp, |
|
4512
|
/* xCheck */ dotCheck, |
|
4513
|
/* xChop */ circleChop, |
|
4514
|
/* xOffset */ dotOffset, |
|
4515
|
/* xFit */ 0, |
|
4516
|
/* xRender */ dotRender |
|
4517
|
}, |
|
4518
|
{ /* name */ "ellipse", |
|
4519
|
/* isline */ 0, |
|
4520
|
/* eJust */ 0, |
|
4521
|
/* xInit */ ellipseInit, |
|
4522
|
/* xNumProp */ 0, |
|
4523
|
/* xCheck */ 0, |
|
4524
|
/* xChop */ ellipseChop, |
|
4525
|
/* xOffset */ ellipseOffset, |
|
4526
|
/* xFit */ boxFit, |
|
4527
|
/* xRender */ ellipseRender |
|
4528
|
}, |
|
4529
|
{ /* name */ "file", |
|
4530
|
/* isline */ 0, |
|
4531
|
/* eJust */ 1, |
|
4532
|
/* xInit */ fileInit, |
|
4533
|
/* xNumProp */ 0, |
|
4534
|
/* xCheck */ 0, |
|
4535
|
/* xChop */ boxChop, |
|
4536
|
/* xOffset */ fileOffset, |
|
4537
|
/* xFit */ fileFit, |
|
4538
|
/* xRender */ fileRender |
|
4539
|
}, |
|
4540
|
{ /* name */ "line", |
|
4541
|
/* isline */ 1, |
|
4542
|
/* eJust */ 0, |
|
4543
|
/* xInit */ lineInit, |
|
4544
|
/* xNumProp */ 0, |
|
4545
|
/* xCheck */ 0, |
|
4546
|
/* xChop */ 0, |
|
4547
|
/* xOffset */ lineOffset, |
|
4548
|
/* xFit */ 0, |
|
4549
|
/* xRender */ splineRender |
|
4550
|
}, |
|
4551
|
{ /* name */ "move", |
|
4552
|
/* isline */ 1, |
|
4553
|
/* eJust */ 0, |
|
4554
|
/* xInit */ moveInit, |
|
4555
|
/* xNumProp */ 0, |
|
4556
|
/* xCheck */ 0, |
|
4557
|
/* xChop */ 0, |
|
4558
|
/* xOffset */ boxOffset, |
|
4559
|
/* xFit */ 0, |
|
4560
|
/* xRender */ moveRender |
|
4561
|
}, |
|
4562
|
{ /* name */ "oval", |
|
4563
|
/* isline */ 0, |
|
4564
|
/* eJust */ 1, |
|
4565
|
/* xInit */ ovalInit, |
|
4566
|
/* xNumProp */ ovalNumProp, |
|
4567
|
/* xCheck */ 0, |
|
4568
|
/* xChop */ boxChop, |
|
4569
|
/* xOffset */ boxOffset, |
|
4570
|
/* xFit */ ovalFit, |
|
4571
|
/* xRender */ boxRender |
|
4572
|
}, |
|
4573
|
{ /* name */ "spline", |
|
4574
|
/* isline */ 1, |
|
4575
|
/* eJust */ 0, |
|
4576
|
/* xInit */ splineInit, |
|
4577
|
/* xNumProp */ 0, |
|
4578
|
/* xCheck */ 0, |
|
4579
|
/* xChop */ 0, |
|
4580
|
/* xOffset */ lineOffset, |
|
4581
|
/* xFit */ 0, |
|
4582
|
/* xRender */ splineRender |
|
4583
|
}, |
|
4584
|
{ /* name */ "text", |
|
4585
|
/* isline */ 0, |
|
4586
|
/* eJust */ 0, |
|
4587
|
/* xInit */ textInit, |
|
4588
|
/* xNumProp */ 0, |
|
4589
|
/* xCheck */ 0, |
|
4590
|
/* xChop */ boxChop, |
|
4591
|
/* xOffset */ textOffset, |
|
4592
|
/* xFit */ boxFit, |
|
4593
|
/* xRender */ textRender |
|
4594
|
}, |
|
4595
|
}; |
|
4596
|
static const PClass sublistClass = |
|
4597
|
{ /* name */ "[]", |
|
4598
|
/* isline */ 0, |
|
4599
|
/* eJust */ 0, |
|
4600
|
/* xInit */ sublistInit, |
|
4601
|
/* xNumProp */ 0, |
|
4602
|
/* xCheck */ 0, |
|
4603
|
/* xChop */ 0, |
|
4604
|
/* xOffset */ boxOffset, |
|
4605
|
/* xFit */ 0, |
|
4606
|
/* xRender */ 0 |
|
4607
|
}; |
|
4608
|
static const PClass noopClass = |
|
4609
|
{ /* name */ "noop", |
|
4610
|
/* isline */ 0, |
|
4611
|
/* eJust */ 0, |
|
4612
|
/* xInit */ 0, |
|
4613
|
/* xNumProp */ 0, |
|
4614
|
/* xCheck */ 0, |
|
4615
|
/* xChop */ 0, |
|
4616
|
/* xOffset */ boxOffset, |
|
4617
|
/* xFit */ 0, |
|
4618
|
/* xRender */ 0 |
|
4619
|
}; |
|
4620
|
|
|
4621
|
|
|
4622
|
/* |
|
4623
|
** Reduce the length of the line segment by amt (if possible) by |
|
4624
|
** modifying the location of *t. |
|
4625
|
*/ |
|
4626
|
static void pik_chop(PPoint *f, PPoint *t, PNum amt){ |
|
4627
|
PNum dx = t->x - f->x; |
|
4628
|
PNum dy = t->y - f->y; |
|
4629
|
PNum dist = hypot(dx,dy); |
|
4630
|
PNum r; |
|
4631
|
if( dist<=amt ){ |
|
4632
|
*t = *f; |
|
4633
|
return; |
|
4634
|
} |
|
4635
|
r = 1.0 - amt/dist; |
|
4636
|
t->x = f->x + r*dx; |
|
4637
|
t->y = f->y + r*dy; |
|
4638
|
} |
|
4639
|
|
|
4640
|
/* |
|
4641
|
** Draw an arrowhead on the end of the line segment from pFrom to pTo. |
|
4642
|
** Also, shorten the line segment (by changing the value of pTo) so that |
|
4643
|
** the shaft of the arrow does not extend into the arrowhead. |
|
4644
|
*/ |
|
4645
|
static void pik_draw_arrowhead(Pik *p, PPoint *f, PPoint *t, PObj *pObj){ |
|
4646
|
PNum dx = t->x - f->x; |
|
4647
|
PNum dy = t->y - f->y; |
|
4648
|
PNum dist = hypot(dx,dy); |
|
4649
|
PNum h = p->hArrow * pObj->sw; |
|
4650
|
PNum w = p->wArrow * pObj->sw; |
|
4651
|
PNum e1, ddx, ddy; |
|
4652
|
PNum bx, by; |
|
4653
|
if( pObj->color<0.0 ) return; |
|
4654
|
if( pObj->sw<=0.0 ) return; |
|
4655
|
if( dist<=0.0 ) return; /* Unable */ |
|
4656
|
dx /= dist; |
|
4657
|
dy /= dist; |
|
4658
|
e1 = dist - h; |
|
4659
|
if( e1<0.0 ){ |
|
4660
|
e1 = 0.0; |
|
4661
|
h = dist; |
|
4662
|
} |
|
4663
|
ddx = -w*dy; |
|
4664
|
ddy = w*dx; |
|
4665
|
bx = f->x + e1*dx; |
|
4666
|
by = f->y + e1*dy; |
|
4667
|
pik_append_xy(p,"<polygon points=\"", t->x, t->y); |
|
4668
|
pik_append_xy(p," ",bx-ddx, by-ddy); |
|
4669
|
pik_append_xy(p," ",bx+ddx, by+ddy); |
|
4670
|
pik_append_clr(p,"\" style=\"fill:",pObj->color,"\"/>\n",0); |
|
4671
|
pik_chop(f,t,h/2); |
|
4672
|
} |
|
4673
|
|
|
4674
|
/* |
|
4675
|
** Compute the relative offset to an edge location from the reference for a |
|
4676
|
** an statement. |
|
4677
|
*/ |
|
4678
|
static PPoint pik_elem_offset(Pik *p, PObj *pObj, int cp){ |
|
4679
|
return pObj->type->xOffset(p, pObj, cp); |
|
4680
|
} |
|
4681
|
|
|
4682
|
|
|
4683
|
/* |
|
4684
|
** Append raw text to zOut |
|
4685
|
*/ |
|
4686
|
static void pik_append(Pik *p, const char *zText, int n){ |
|
4687
|
if( n<0 ) n = (int)strlen(zText); |
|
4688
|
if( p->nOut+n>=p->nOutAlloc ){ |
|
4689
|
int nNew = (p->nOut+n)*2 + 1; |
|
4690
|
char *z = realloc(p->zOut, nNew); |
|
4691
|
if( z==0 ){ |
|
4692
|
pik_error(p, 0, 0); |
|
4693
|
return; |
|
4694
|
} |
|
4695
|
p->zOut = z; |
|
4696
|
p->nOutAlloc = nNew; |
|
4697
|
} |
|
4698
|
memcpy(p->zOut+p->nOut, zText, n); |
|
4699
|
p->nOut += n; |
|
4700
|
p->zOut[p->nOut] = 0; |
|
4701
|
} |
|
4702
|
|
|
4703
|
/* |
|
4704
|
** Given a string and its length, returns true if the string begins |
|
4705
|
** with a construct which syntactically matches an HTML entity escape |
|
4706
|
** sequence (without checking for whether it's a known entity). Always |
|
4707
|
** returns false if zText[0] is false or n<4. Entities match the |
|
4708
|
** equivalent of the regexes `&#[0-9]{2,};` and |
|
4709
|
** `&[a-zA-Z][a-zA-Z0-9]+;`. |
|
4710
|
*/ |
|
4711
|
static int pik_isentity(char const * zText, int n){ |
|
4712
|
int i = 0; |
|
4713
|
if( n<4 || '&'!=zText[0] ) return 0; |
|
4714
|
n--; |
|
4715
|
zText++; |
|
4716
|
if( '#'==zText[0] ){ |
|
4717
|
zText++; |
|
4718
|
n--; |
|
4719
|
for(i=0; i<n; i++){ |
|
4720
|
if( i>1 && ';'==zText[i] ) return 1; |
|
4721
|
else if( zText[i]<'0' || zText[i]>'9' ) return 0; |
|
4722
|
/* Note that &#nn; values nn<32d are not legal entities. */ |
|
4723
|
} |
|
4724
|
}else{ |
|
4725
|
for(i=0; i<n; i++){ |
|
4726
|
if( i>1 && ';'==zText[i] ) return 1; |
|
4727
|
else if( i>0 && zText[i]>='0' && zText[i]<='9' ){ |
|
4728
|
continue; |
|
4729
|
}else if( zText[i]<'A' || zText[i]>'z' |
|
4730
|
|| (zText[i]>'Z' && zText[i]<'a') ) return 0; |
|
4731
|
} |
|
4732
|
} |
|
4733
|
return 0; |
|
4734
|
} |
|
4735
|
|
|
4736
|
/* |
|
4737
|
** Append text to zOut with HTML characters escaped. |
|
4738
|
** |
|
4739
|
** * The space character is changed into non-breaking space (U+00a0) |
|
4740
|
** if mFlags has the 0x01 bit set. This is needed when outputting |
|
4741
|
** text to preserve leading and trailing whitespace. Turns out we |
|
4742
|
** cannot use as that is an HTML-ism and is not valid in XML. |
|
4743
|
** |
|
4744
|
** * The "&" character is changed into "&" if mFlags has the |
|
4745
|
** 0x02 bit set. This is needed when generating error message text. |
|
4746
|
** |
|
4747
|
** * Except for the above, only "<" and ">" are escaped. |
|
4748
|
*/ |
|
4749
|
static void pik_append_text(Pik *p, const char *zText, int n, int mFlags){ |
|
4750
|
int i; |
|
4751
|
char c = 0; |
|
4752
|
int bQSpace = mFlags & 1; |
|
4753
|
int bQAmp = mFlags & 2; |
|
4754
|
if( n<0 ) n = (int)strlen(zText); |
|
4755
|
while( n>0 ){ |
|
4756
|
for(i=0; i<n; i++){ |
|
4757
|
c = zText[i]; |
|
4758
|
if( c=='<' || c=='>' ) break; |
|
4759
|
if( c==' ' && bQSpace ) break; |
|
4760
|
if( c=='&' && bQAmp ) break; |
|
4761
|
} |
|
4762
|
if( i ) pik_append(p, zText, i); |
|
4763
|
if( i==n ) break; |
|
4764
|
switch( c ){ |
|
4765
|
case '<': { pik_append(p, "<", 4); break; } |
|
4766
|
case '>': { pik_append(p, ">", 4); break; } |
|
4767
|
case ' ': { pik_append(p, "\302\240;", 2); break; } |
|
4768
|
case '&': |
|
4769
|
if( pik_isentity(zText+i, n-i) ){ pik_append(p, "&", 1); } |
|
4770
|
else { pik_append(p, "&", 5); } |
|
4771
|
} |
|
4772
|
i++; |
|
4773
|
n -= i; |
|
4774
|
zText += i; |
|
4775
|
i = 0; |
|
4776
|
} |
|
4777
|
} |
|
4778
|
|
|
4779
|
/* |
|
4780
|
** Append error message text. This is either a raw append, or an append |
|
4781
|
** with HTML escapes, depending on whether the PIKCHR_PLAINTEXT_ERRORS flag |
|
4782
|
** is set. |
|
4783
|
*/ |
|
4784
|
static void pik_append_errtxt(Pik *p, const char *zText, int n){ |
|
4785
|
if( p->mFlags & PIKCHR_PLAINTEXT_ERRORS ){ |
|
4786
|
pik_append(p, zText, n); |
|
4787
|
}else{ |
|
4788
|
pik_append_text(p, zText, n, 0); |
|
4789
|
} |
|
4790
|
} |
|
4791
|
|
|
4792
|
/* Append a PNum value |
|
4793
|
*/ |
|
4794
|
static void pik_append_num(Pik *p, const char *z,PNum v){ |
|
4795
|
char buf[100]; |
|
4796
|
snprintf(buf, sizeof(buf)-1, "%.10g", (double)v); |
|
4797
|
buf[sizeof(buf)-1] = 0; |
|
4798
|
pik_append(p, z, -1); |
|
4799
|
pik_append(p, buf, -1); |
|
4800
|
} |
|
4801
|
|
|
4802
|
/* Append a PPoint value (Used for debugging only) |
|
4803
|
*/ |
|
4804
|
static void pik_append_point(Pik *p, const char *z, PPoint *pPt){ |
|
4805
|
char buf[100]; |
|
4806
|
snprintf(buf, sizeof(buf)-1, "%.10g,%.10g", |
|
4807
|
(double)pPt->x, (double)pPt->y); |
|
4808
|
buf[sizeof(buf)-1] = 0; |
|
4809
|
pik_append(p, z, -1); |
|
4810
|
pik_append(p, buf, -1); |
|
4811
|
} |
|
4812
|
|
|
4813
|
/* |
|
4814
|
** Invert the RGB color so that it is appropriate for dark mode. |
|
4815
|
** Variable x hold the initial color. The color is intended for use |
|
4816
|
** as a background color if isBg is true, and as a foreground color |
|
4817
|
** if isBg is false. |
|
4818
|
*/ |
|
4819
|
static int pik_color_to_dark_mode(int x, int isBg){ |
|
4820
|
int r, g, b; |
|
4821
|
int mn, mx; |
|
4822
|
x = 0xffffff - x; |
|
4823
|
r = (x>>16) & 0xff; |
|
4824
|
g = (x>>8) & 0xff; |
|
4825
|
b = x & 0xff; |
|
4826
|
mx = r; |
|
4827
|
if( g>mx ) mx = g; |
|
4828
|
if( b>mx ) mx = b; |
|
4829
|
mn = r; |
|
4830
|
if( g<mn ) mn = g; |
|
4831
|
if( b<mn ) mn = b; |
|
4832
|
r = mn + (mx-r); |
|
4833
|
g = mn + (mx-g); |
|
4834
|
b = mn + (mx-b); |
|
4835
|
if( isBg ){ |
|
4836
|
if( mx>127 ){ |
|
4837
|
r = (127*r)/mx; |
|
4838
|
g = (127*g)/mx; |
|
4839
|
b = (127*b)/mx; |
|
4840
|
} |
|
4841
|
}else{ |
|
4842
|
if( mn<128 && mx>mn ){ |
|
4843
|
r = 127 + ((r-mn)*128)/(mx-mn); |
|
4844
|
g = 127 + ((g-mn)*128)/(mx-mn); |
|
4845
|
b = 127 + ((b-mn)*128)/(mx-mn); |
|
4846
|
} |
|
4847
|
} |
|
4848
|
return r*0x10000 + g*0x100 + b; |
|
4849
|
} |
|
4850
|
|
|
4851
|
/* Append a PNum value surrounded by text. Do coordinate transformations |
|
4852
|
** on the value. |
|
4853
|
*/ |
|
4854
|
static void pik_append_x(Pik *p, const char *z1, PNum v, const char *z2){ |
|
4855
|
char buf[200]; |
|
4856
|
v -= p->bbox.sw.x; |
|
4857
|
snprintf(buf, sizeof(buf)-1, "%s%g%s", z1, p->rScale*v, z2); |
|
4858
|
buf[sizeof(buf)-1] = 0; |
|
4859
|
pik_append(p, buf, -1); |
|
4860
|
} |
|
4861
|
static void pik_append_y(Pik *p, const char *z1, PNum v, const char *z2){ |
|
4862
|
char buf[200]; |
|
4863
|
v = p->bbox.ne.y - v; |
|
4864
|
snprintf(buf, sizeof(buf)-1, "%s%g%s", z1, p->rScale*v, z2); |
|
4865
|
buf[sizeof(buf)-1] = 0; |
|
4866
|
pik_append(p, buf, -1); |
|
4867
|
} |
|
4868
|
static void pik_append_xy(Pik *p, const char *z1, PNum x, PNum y){ |
|
4869
|
char buf[200]; |
|
4870
|
x = x - p->bbox.sw.x; |
|
4871
|
y = p->bbox.ne.y - y; |
|
4872
|
snprintf(buf, sizeof(buf)-1, "%s%g,%g", z1, p->rScale*x, p->rScale*y); |
|
4873
|
buf[sizeof(buf)-1] = 0; |
|
4874
|
pik_append(p, buf, -1); |
|
4875
|
} |
|
4876
|
static void pik_append_dis(Pik *p, const char *z1, PNum v, const char *z2){ |
|
4877
|
char buf[200]; |
|
4878
|
snprintf(buf, sizeof(buf)-1, "%s%g%s", z1, p->rScale*v, z2); |
|
4879
|
buf[sizeof(buf)-1] = 0; |
|
4880
|
pik_append(p, buf, -1); |
|
4881
|
} |
|
4882
|
|
|
4883
|
/* Append a color specification to the output. |
|
4884
|
** |
|
4885
|
** In PIKCHR_DARK_MODE, the color is inverted. The "bg" flags indicates that |
|
4886
|
** the color is intended for use as a background color if true, or as a |
|
4887
|
** foreground color if false. The distinction only matters for color |
|
4888
|
** inversions in PIKCHR_DARK_MODE. |
|
4889
|
*/ |
|
4890
|
static void pik_append_clr(Pik *p,const char *z1,PNum v,const char *z2,int bg){ |
|
4891
|
char buf[200]; |
|
4892
|
int x = pik_round(v); |
|
4893
|
int r, g, b; |
|
4894
|
if( x==0 && p->fgcolor>0 && !bg ){ |
|
4895
|
x = p->fgcolor; |
|
4896
|
}else if( bg && x>=0xffffff && p->bgcolor>0 ){ |
|
4897
|
x = p->bgcolor; |
|
4898
|
}else if( p->mFlags & PIKCHR_DARK_MODE ){ |
|
4899
|
x = pik_color_to_dark_mode(x,bg); |
|
4900
|
} |
|
4901
|
r = (x>>16) & 0xff; |
|
4902
|
g = (x>>8) & 0xff; |
|
4903
|
b = x & 0xff; |
|
4904
|
snprintf(buf, sizeof(buf)-1, "%srgb(%d,%d,%d)%s", z1, r, g, b, z2); |
|
4905
|
buf[sizeof(buf)-1] = 0; |
|
4906
|
pik_append(p, buf, -1); |
|
4907
|
} |
|
4908
|
|
|
4909
|
/* Append an SVG path A record: |
|
4910
|
** |
|
4911
|
** A r1 r2 0 0 0 x y |
|
4912
|
*/ |
|
4913
|
static void pik_append_arc(Pik *p, PNum r1, PNum r2, PNum x, PNum y){ |
|
4914
|
char buf[200]; |
|
4915
|
x = x - p->bbox.sw.x; |
|
4916
|
y = p->bbox.ne.y - y; |
|
4917
|
snprintf(buf, sizeof(buf)-1, "A%g %g 0 0 0 %g %g", |
|
4918
|
p->rScale*r1, p->rScale*r2, |
|
4919
|
p->rScale*x, p->rScale*y); |
|
4920
|
buf[sizeof(buf)-1] = 0; |
|
4921
|
pik_append(p, buf, -1); |
|
4922
|
} |
|
4923
|
|
|
4924
|
/* Append a style="..." text. But, leave the quote unterminated, in case |
|
4925
|
** the caller wants to add some more. |
|
4926
|
** |
|
4927
|
** eFill is non-zero to fill in the background, or 0 if no fill should |
|
4928
|
** occur. Non-zero values of eFill determine the "bg" flag to pik_append_clr() |
|
4929
|
** for cases when pObj->fill==pObj->color |
|
4930
|
** |
|
4931
|
** 1 fill is background, and color is foreground. |
|
4932
|
** 2 fill and color are both foreground. (Used by "dot" objects) |
|
4933
|
** 3 fill and color are both background. (Used by most other objs) |
|
4934
|
*/ |
|
4935
|
static void pik_append_style(Pik *p, PObj *pObj, int eFill){ |
|
4936
|
int clrIsBg = 0; |
|
4937
|
pik_append(p, " style=\"", -1); |
|
4938
|
if( pObj->fill>=0 && eFill ){ |
|
4939
|
int fillIsBg = 1; |
|
4940
|
if( pObj->fill==pObj->color ){ |
|
4941
|
if( eFill==2 ) fillIsBg = 0; |
|
4942
|
if( eFill==3 ) clrIsBg = 1; |
|
4943
|
} |
|
4944
|
pik_append_clr(p, "fill:", pObj->fill, ";", fillIsBg); |
|
4945
|
}else{ |
|
4946
|
pik_append(p,"fill:none;",-1); |
|
4947
|
} |
|
4948
|
if( pObj->sw>=0.0 && pObj->color>=0.0 ){ |
|
4949
|
PNum sw = pObj->sw; |
|
4950
|
pik_append_dis(p, "stroke-width:", sw, ";"); |
|
4951
|
if( pObj->nPath>2 && pObj->rad<=pObj->sw ){ |
|
4952
|
pik_append(p, "stroke-linejoin:round;", -1); |
|
4953
|
} |
|
4954
|
pik_append_clr(p, "stroke:",pObj->color,";",clrIsBg); |
|
4955
|
if( pObj->dotted>0.0 ){ |
|
4956
|
PNum v = pObj->dotted; |
|
4957
|
if( sw<2.1/p->rScale ) sw = 2.1/p->rScale; |
|
4958
|
pik_append_dis(p,"stroke-dasharray:",sw,""); |
|
4959
|
pik_append_dis(p,",",v,";"); |
|
4960
|
}else if( pObj->dashed>0.0 ){ |
|
4961
|
PNum v = pObj->dashed; |
|
4962
|
pik_append_dis(p,"stroke-dasharray:",v,""); |
|
4963
|
pik_append_dis(p,",",v,";"); |
|
4964
|
} |
|
4965
|
} |
|
4966
|
} |
|
4967
|
|
|
4968
|
/* |
|
4969
|
** Compute the vertical locations for all text items in the |
|
4970
|
** object pObj. In other words, set every pObj->aTxt[*].eCode |
|
4971
|
** value to contain exactly one of: TP_ABOVE2, TP_ABOVE, TP_CENTER, |
|
4972
|
** TP_BELOW, or TP_BELOW2 is set. |
|
4973
|
*/ |
|
4974
|
static void pik_txt_vertical_layout(PObj *pObj){ |
|
4975
|
int n, i; |
|
4976
|
PToken *aTxt; |
|
4977
|
n = pObj->nTxt; |
|
4978
|
if( n==0 ) return; |
|
4979
|
aTxt = pObj->aTxt; |
|
4980
|
if( n==1 ){ |
|
4981
|
if( (aTxt[0].eCode & TP_VMASK)==0 ){ |
|
4982
|
aTxt[0].eCode |= TP_CENTER; |
|
4983
|
} |
|
4984
|
}else{ |
|
4985
|
int allSlots = 0; |
|
4986
|
int aFree[5]; |
|
4987
|
int iSlot; |
|
4988
|
int j, mJust; |
|
4989
|
/* If there is more than one TP_ABOVE, change the first to TP_ABOVE2. */ |
|
4990
|
for(j=mJust=0, i=n-1; i>=0; i--){ |
|
4991
|
if( aTxt[i].eCode & TP_ABOVE ){ |
|
4992
|
if( j==0 ){ |
|
4993
|
j++; |
|
4994
|
mJust = aTxt[i].eCode & TP_JMASK; |
|
4995
|
}else if( j==1 && mJust!=0 && (aTxt[i].eCode & mJust)==0 ){ |
|
4996
|
j++; |
|
4997
|
}else{ |
|
4998
|
aTxt[i].eCode = (aTxt[i].eCode & ~TP_VMASK) | TP_ABOVE2; |
|
4999
|
break; |
|
5000
|
} |
|
5001
|
} |
|
5002
|
} |
|
5003
|
/* If there is more than one TP_BELOW, change the last to TP_BELOW2 */ |
|
5004
|
for(j=mJust=0, i=0; i<n; i++){ |
|
5005
|
if( aTxt[i].eCode & TP_BELOW ){ |
|
5006
|
if( j==0 ){ |
|
5007
|
j++; |
|
5008
|
mJust = aTxt[i].eCode & TP_JMASK; |
|
5009
|
}else if( j==1 && mJust!=0 && (aTxt[i].eCode & mJust)==0 ){ |
|
5010
|
j++; |
|
5011
|
}else{ |
|
5012
|
aTxt[i].eCode = (aTxt[i].eCode & ~TP_VMASK) | TP_BELOW2; |
|
5013
|
break; |
|
5014
|
} |
|
5015
|
} |
|
5016
|
} |
|
5017
|
/* Compute a mask of all slots used */ |
|
5018
|
for(i=0; i<n; i++) allSlots |= aTxt[i].eCode & TP_VMASK; |
|
5019
|
/* Set of an array of available slots */ |
|
5020
|
if( n==2 |
|
5021
|
&& ((aTxt[0].eCode|aTxt[1].eCode)&TP_JMASK)==(TP_LJUST|TP_RJUST) |
|
5022
|
){ |
|
5023
|
/* Special case of two texts that have opposite justification: |
|
5024
|
** Allow them both to float to center. */ |
|
5025
|
iSlot = 2; |
|
5026
|
aFree[0] = aFree[1] = TP_CENTER; |
|
5027
|
}else{ |
|
5028
|
/* Set up the arrow so that available slots are filled from top to |
|
5029
|
** bottom */ |
|
5030
|
iSlot = 0; |
|
5031
|
if( n>=4 && (allSlots & TP_ABOVE2)==0 ) aFree[iSlot++] = TP_ABOVE2; |
|
5032
|
if( (allSlots & TP_ABOVE)==0 ) aFree[iSlot++] = TP_ABOVE; |
|
5033
|
if( (n&1)!=0 ) aFree[iSlot++] = TP_CENTER; |
|
5034
|
if( (allSlots & TP_BELOW)==0 ) aFree[iSlot++] = TP_BELOW; |
|
5035
|
if( n>=4 && (allSlots & TP_BELOW2)==0 ) aFree[iSlot++] = TP_BELOW2; |
|
5036
|
} |
|
5037
|
/* Set the VMASK for all unassigned texts */ |
|
5038
|
for(i=iSlot=0; i<n; i++){ |
|
5039
|
if( (aTxt[i].eCode & TP_VMASK)==0 ){ |
|
5040
|
aTxt[i].eCode |= aFree[iSlot++]; |
|
5041
|
} |
|
5042
|
} |
|
5043
|
} |
|
5044
|
} |
|
5045
|
|
|
5046
|
/* Return the font scaling factor associated with the input text attribute. |
|
5047
|
*/ |
|
5048
|
static PNum pik_font_scale(PToken *t){ |
|
5049
|
PNum scale = 1.0; |
|
5050
|
if( t->eCode & TP_BIG ) scale *= 1.25; |
|
5051
|
if( t->eCode & TP_SMALL ) scale *= 0.8; |
|
5052
|
if( t->eCode & TP_XTRA ) scale *= scale; |
|
5053
|
return scale; |
|
5054
|
} |
|
5055
|
|
|
5056
|
/* Append multiple <text> SVG elements for the text fields of the PObj. |
|
5057
|
** Parameters: |
|
5058
|
** |
|
5059
|
** p The Pik object into which we are rendering |
|
5060
|
** |
|
5061
|
** pObj Object containing the text to be rendered |
|
5062
|
** |
|
5063
|
** pBox If not NULL, do no rendering at all. Instead |
|
5064
|
** expand the box object so that it will include all |
|
5065
|
** of the text. |
|
5066
|
*/ |
|
5067
|
static void pik_append_txt(Pik *p, PObj *pObj, PBox *pBox){ |
|
5068
|
PNum jw; /* Justification margin relative to center */ |
|
5069
|
PNum ha2 = 0.0; /* Height of the top row of text */ |
|
5070
|
PNum ha1 = 0.0; /* Height of the second "above" row */ |
|
5071
|
PNum hc = 0.0; /* Height of the center row */ |
|
5072
|
PNum hb1 = 0.0; /* Height of the first "below" row of text */ |
|
5073
|
PNum hb2 = 0.0; /* Height of the second "below" row */ |
|
5074
|
PNum yBase = 0.0; |
|
5075
|
PNum sw = pObj->sw>=0.0 ? pObj->sw : 0; |
|
5076
|
int n, i, nz; |
|
5077
|
PNum x, y, orig_y, s; |
|
5078
|
const char *z; |
|
5079
|
PToken *aTxt; |
|
5080
|
unsigned allMask = 0; |
|
5081
|
|
|
5082
|
if( p->nErr ) return; |
|
5083
|
if( pObj->nTxt==0 ) return; |
|
5084
|
aTxt = pObj->aTxt; |
|
5085
|
n = pObj->nTxt; |
|
5086
|
pik_txt_vertical_layout(pObj); |
|
5087
|
x = pObj->ptAt.x; |
|
5088
|
for(i=0; i<n; i++) allMask |= pObj->aTxt[i].eCode; |
|
5089
|
if( pObj->type->isLine ){ |
|
5090
|
hc = sw*1.5; |
|
5091
|
}else if( pObj->rad>0.0 && pObj->type->xInit==cylinderInit ){ |
|
5092
|
yBase = -0.75*pObj->rad; |
|
5093
|
} |
|
5094
|
if( allMask & TP_CENTER ){ |
|
5095
|
for(i=0; i<n; i++){ |
|
5096
|
if( pObj->aTxt[i].eCode & TP_CENTER ){ |
|
5097
|
s = pik_font_scale(pObj->aTxt+i); |
|
5098
|
if( hc<s*p->charHeight ) hc = s*p->charHeight; |
|
5099
|
} |
|
5100
|
} |
|
5101
|
} |
|
5102
|
if( allMask & TP_ABOVE ){ |
|
5103
|
for(i=0; i<n; i++){ |
|
5104
|
if( pObj->aTxt[i].eCode & TP_ABOVE ){ |
|
5105
|
s = pik_font_scale(pObj->aTxt+i)*p->charHeight; |
|
5106
|
if( ha1<s ) ha1 = s; |
|
5107
|
} |
|
5108
|
} |
|
5109
|
if( allMask & TP_ABOVE2 ){ |
|
5110
|
for(i=0; i<n; i++){ |
|
5111
|
if( pObj->aTxt[i].eCode & TP_ABOVE2 ){ |
|
5112
|
s = pik_font_scale(pObj->aTxt+i)*p->charHeight; |
|
5113
|
if( ha2<s ) ha2 = s; |
|
5114
|
} |
|
5115
|
} |
|
5116
|
} |
|
5117
|
} |
|
5118
|
if( allMask & TP_BELOW ){ |
|
5119
|
for(i=0; i<n; i++){ |
|
5120
|
if( pObj->aTxt[i].eCode & TP_BELOW ){ |
|
5121
|
s = pik_font_scale(pObj->aTxt+i)*p->charHeight; |
|
5122
|
if( hb1<s ) hb1 = s; |
|
5123
|
} |
|
5124
|
} |
|
5125
|
if( allMask & TP_BELOW2 ){ |
|
5126
|
for(i=0; i<n; i++){ |
|
5127
|
if( pObj->aTxt[i].eCode & TP_BELOW2 ){ |
|
5128
|
s = pik_font_scale(pObj->aTxt+i)*p->charHeight; |
|
5129
|
if( hb2<s ) hb2 = s; |
|
5130
|
} |
|
5131
|
} |
|
5132
|
} |
|
5133
|
} |
|
5134
|
if( pObj->type->eJust==1 ){ |
|
5135
|
jw = 0.5*(pObj->w - 0.5*(p->charWidth + sw)); |
|
5136
|
}else{ |
|
5137
|
jw = 0.0; |
|
5138
|
} |
|
5139
|
for(i=0; i<n; i++){ |
|
5140
|
PToken *t = &aTxt[i]; |
|
5141
|
PNum xtraFontScale = pik_font_scale(t); |
|
5142
|
PNum nx = 0; |
|
5143
|
orig_y = pObj->ptAt.y; |
|
5144
|
y = yBase; |
|
5145
|
if( t->eCode & TP_ABOVE2 ) y += 0.5*hc + ha1 + 0.5*ha2; |
|
5146
|
if( t->eCode & TP_ABOVE ) y += 0.5*hc + 0.5*ha1; |
|
5147
|
if( t->eCode & TP_BELOW ) y -= 0.5*hc + 0.5*hb1; |
|
5148
|
if( t->eCode & TP_BELOW2 ) y -= 0.5*hc + hb1 + 0.5*hb2; |
|
5149
|
if( t->eCode & TP_LJUST ) nx -= jw; |
|
5150
|
if( t->eCode & TP_RJUST ) nx += jw; |
|
5151
|
|
|
5152
|
if( pBox!=0 ){ |
|
5153
|
/* If pBox is not NULL, do not draw any <text>. Instead, just expand |
|
5154
|
** pBox to include the text */ |
|
5155
|
PNum cw = pik_text_length(t, t->eCode & TP_MONO)*p->charWidth*xtraFontScale*0.01; |
|
5156
|
PNum ch = p->charHeight*0.5*xtraFontScale; |
|
5157
|
PNum x0, y0, x1, y1; /* Boundary of text relative to pObj->ptAt */ |
|
5158
|
if( (t->eCode & (TP_BOLD|TP_MONO))==TP_BOLD ){ |
|
5159
|
cw *= 1.1; |
|
5160
|
} |
|
5161
|
if( t->eCode & TP_RJUST ){ |
|
5162
|
x0 = nx; |
|
5163
|
y0 = y-ch; |
|
5164
|
x1 = nx-cw; |
|
5165
|
y1 = y+ch; |
|
5166
|
}else if( t->eCode & TP_LJUST ){ |
|
5167
|
x0 = nx; |
|
5168
|
y0 = y-ch; |
|
5169
|
x1 = nx+cw; |
|
5170
|
y1 = y+ch; |
|
5171
|
}else{ |
|
5172
|
x0 = nx+cw/2; |
|
5173
|
y0 = y+ch; |
|
5174
|
x1 = nx-cw/2; |
|
5175
|
y1 = y-ch; |
|
5176
|
} |
|
5177
|
if( (t->eCode & TP_ALIGN)!=0 && pObj->nPath>=2 ){ |
|
5178
|
int nn = pObj->nPath; |
|
5179
|
PNum dx = pObj->aPath[nn-1].x - pObj->aPath[0].x; |
|
5180
|
PNum dy = pObj->aPath[nn-1].y - pObj->aPath[0].y; |
|
5181
|
if( dx!=0 || dy!=0 ){ |
|
5182
|
PNum dist = hypot(dx,dy); |
|
5183
|
PNum tt; |
|
5184
|
dx /= dist; |
|
5185
|
dy /= dist; |
|
5186
|
tt = dx*x0 - dy*y0; |
|
5187
|
y0 = dy*x0 - dx*y0; |
|
5188
|
x0 = tt; |
|
5189
|
tt = dx*x1 - dy*y1; |
|
5190
|
y1 = dy*x1 - dx*y1; |
|
5191
|
x1 = tt; |
|
5192
|
} |
|
5193
|
} |
|
5194
|
pik_bbox_add_xy(pBox, x+x0, orig_y+y0); |
|
5195
|
pik_bbox_add_xy(pBox, x+x1, orig_y+y1); |
|
5196
|
continue; |
|
5197
|
} |
|
5198
|
nx += x; |
|
5199
|
y += orig_y; |
|
5200
|
|
|
5201
|
pik_append_x(p, "<text x=\"", nx, "\""); |
|
5202
|
pik_append_y(p, " y=\"", y, "\""); |
|
5203
|
if( t->eCode & TP_RJUST ){ |
|
5204
|
pik_append(p, " text-anchor=\"end\"", -1); |
|
5205
|
}else if( t->eCode & TP_LJUST ){ |
|
5206
|
pik_append(p, " text-anchor=\"start\"", -1); |
|
5207
|
}else{ |
|
5208
|
pik_append(p, " text-anchor=\"middle\"", -1); |
|
5209
|
} |
|
5210
|
if( t->eCode & TP_ITALIC ){ |
|
5211
|
pik_append(p, " font-style=\"italic\"", -1); |
|
5212
|
} |
|
5213
|
if( t->eCode & TP_BOLD ){ |
|
5214
|
pik_append(p, " font-weight=\"bold\"", -1); |
|
5215
|
} |
|
5216
|
if( t->eCode & TP_MONO ){ |
|
5217
|
pik_append(p, " font-family=\"monospace\"", -1); |
|
5218
|
} |
|
5219
|
if( pObj->color>=0.0 ){ |
|
5220
|
pik_append_clr(p, " fill=\"", pObj->color, "\"",0); |
|
5221
|
} |
|
5222
|
xtraFontScale *= p->fontScale; |
|
5223
|
if( xtraFontScale<=0.99 || xtraFontScale>=1.01 ){ |
|
5224
|
pik_append_num(p, " font-size=\"", xtraFontScale*100.0); |
|
5225
|
pik_append(p, "%\"", 2); |
|
5226
|
} |
|
5227
|
if( (t->eCode & TP_ALIGN)!=0 && pObj->nPath>=2 ){ |
|
5228
|
int nn = pObj->nPath; |
|
5229
|
PNum dx = pObj->aPath[nn-1].x - pObj->aPath[0].x; |
|
5230
|
PNum dy = pObj->aPath[nn-1].y - pObj->aPath[0].y; |
|
5231
|
if( dx!=0 || dy!=0 ){ |
|
5232
|
PNum ang = atan2(dy,dx)*-180/M_PI; |
|
5233
|
pik_append_num(p, " transform=\"rotate(", ang); |
|
5234
|
pik_append_xy(p, " ", x, orig_y); |
|
5235
|
pik_append(p,")\"",2); |
|
5236
|
} |
|
5237
|
} |
|
5238
|
pik_append(p," dominant-baseline=\"central\">",-1); |
|
5239
|
if( t->n>=2 && t->z[0]=='"' ){ |
|
5240
|
z = t->z+1; |
|
5241
|
nz = t->n-2; |
|
5242
|
}else{ |
|
5243
|
z = t->z; |
|
5244
|
nz = t->n; |
|
5245
|
} |
|
5246
|
while( nz>0 ){ |
|
5247
|
int j; |
|
5248
|
for(j=0; j<nz && z[j]!='\\'; j++){} |
|
5249
|
if( j ) pik_append_text(p, z, j, 0x3); |
|
5250
|
if( j<nz && (j+1==nz || z[j+1]=='\\') ){ |
|
5251
|
pik_append(p, "\", -1); |
|
5252
|
j++; |
|
5253
|
} |
|
5254
|
nz -= j+1; |
|
5255
|
z += j+1; |
|
5256
|
} |
|
5257
|
pik_append(p, "</text>\n", -1); |
|
5258
|
} |
|
5259
|
} |
|
5260
|
|
|
5261
|
/* |
|
5262
|
** Append text (that will go inside of a <pre>...</pre>) that |
|
5263
|
** shows the context of an error token. |
|
5264
|
*/ |
|
5265
|
static void pik_error_context(Pik *p, PToken *pErr, int nContext){ |
|
5266
|
int iErrPt; /* Index of first byte of error from start of input */ |
|
5267
|
int iErrCol; /* Column of the error token on its line */ |
|
5268
|
int iStart; /* Start position of the error context */ |
|
5269
|
int iEnd; /* End position of the error context */ |
|
5270
|
int iLineno; /* Line number of the error */ |
|
5271
|
int iFirstLineno; /* Line number of start of error context */ |
|
5272
|
int i; /* Loop counter */ |
|
5273
|
int iBump = 0; /* Bump the location of the error cursor */ |
|
5274
|
char zLineno[24]; /* Buffer in which to generate line numbers */ |
|
5275
|
|
|
5276
|
iErrPt = (int)(pErr->z - p->sIn.z); |
|
5277
|
if( iErrPt>=(int)p->sIn.n ){ |
|
5278
|
iErrPt = p->sIn.n-1; |
|
5279
|
iBump = 1; |
|
5280
|
}else{ |
|
5281
|
while( iErrPt>0 && (p->sIn.z[iErrPt]=='\n' || p->sIn.z[iErrPt]=='\r') ){ |
|
5282
|
iErrPt--; |
|
5283
|
iBump = 1; |
|
5284
|
} |
|
5285
|
} |
|
5286
|
iLineno = 1; |
|
5287
|
for(i=0; i<iErrPt; i++){ |
|
5288
|
if( p->sIn.z[i]=='\n' ){ |
|
5289
|
iLineno++; |
|
5290
|
} |
|
5291
|
} |
|
5292
|
iStart = 0; |
|
5293
|
iFirstLineno = 1; |
|
5294
|
while( iFirstLineno+nContext<iLineno ){ |
|
5295
|
while( p->sIn.z[iStart]!='\n' ){ iStart++; } |
|
5296
|
iStart++; |
|
5297
|
iFirstLineno++; |
|
5298
|
} |
|
5299
|
for(iEnd=iErrPt; p->sIn.z[iEnd]!=0 && p->sIn.z[iEnd]!='\n'; iEnd++){} |
|
5300
|
i = iStart; |
|
5301
|
while( iFirstLineno<=iLineno ){ |
|
5302
|
snprintf(zLineno,sizeof(zLineno)-1,"/* %4d */ ", iFirstLineno++); |
|
5303
|
zLineno[sizeof(zLineno)-1] = 0; |
|
5304
|
pik_append(p, zLineno, -1); |
|
5305
|
for(i=iStart; p->sIn.z[i]!=0 && p->sIn.z[i]!='\n'; i++){} |
|
5306
|
pik_append_errtxt(p, p->sIn.z+iStart, i-iStart); |
|
5307
|
iStart = i+1; |
|
5308
|
pik_append(p, "\n", 1); |
|
5309
|
} |
|
5310
|
for(iErrCol=0, i=iErrPt; i>0 && p->sIn.z[i]!='\n'; iErrCol++, i--){} |
|
5311
|
for(i=0; i<iErrCol+11+iBump; i++){ pik_append(p, " ", 1); } |
|
5312
|
for(i=0; i<(int)pErr->n; i++) pik_append(p, "^", 1); |
|
5313
|
pik_append(p, "\n", 1); |
|
5314
|
} |
|
5315
|
|
|
5316
|
|
|
5317
|
/* |
|
5318
|
** Generate an error message for the output. pErr is the token at which |
|
5319
|
** the error should point. zMsg is the text of the error message. If |
|
5320
|
** either pErr or zMsg is NULL, generate an out-of-memory error message. |
|
5321
|
** |
|
5322
|
** This routine is a no-op if there has already been an error reported. |
|
5323
|
*/ |
|
5324
|
static void pik_error(Pik *p, PToken *pErr, const char *zMsg){ |
|
5325
|
int i; |
|
5326
|
if( p==0 ) return; |
|
5327
|
if( p->nErr ) return; |
|
5328
|
p->nErr++; |
|
5329
|
if( zMsg==0 ){ |
|
5330
|
if( p->mFlags & PIKCHR_PLAINTEXT_ERRORS ){ |
|
5331
|
pik_append(p, "\nOut of memory\n", -1); |
|
5332
|
}else{ |
|
5333
|
pik_append(p, "\n<div><p>Out of memory</p></div>\n", -1); |
|
5334
|
} |
|
5335
|
return; |
|
5336
|
} |
|
5337
|
if( pErr==0 ){ |
|
5338
|
pik_append(p, "\n", 1); |
|
5339
|
pik_append_errtxt(p, zMsg, -1); |
|
5340
|
return; |
|
5341
|
} |
|
5342
|
if( (p->mFlags & PIKCHR_PLAINTEXT_ERRORS)==0 ){ |
|
5343
|
pik_append(p, "<div><pre>\n", -1); |
|
5344
|
} |
|
5345
|
pik_error_context(p, pErr, 5); |
|
5346
|
pik_append(p, "ERROR: ", -1); |
|
5347
|
pik_append_errtxt(p, zMsg, -1); |
|
5348
|
pik_append(p, "\n", 1); |
|
5349
|
for(i=p->nCtx-1; i>=0; i--){ |
|
5350
|
pik_append(p, "Called from:\n", -1); |
|
5351
|
pik_error_context(p, &p->aCtx[i], 0); |
|
5352
|
} |
|
5353
|
if( (p->mFlags & PIKCHR_PLAINTEXT_ERRORS)==0 ){ |
|
5354
|
pik_append(p, "</pre></div>\n", -1); |
|
5355
|
} |
|
5356
|
} |
|
5357
|
|
|
5358
|
/* |
|
5359
|
** Process an "assert( e1 == e2 )" statement. Always return NULL. |
|
5360
|
*/ |
|
5361
|
static PObj *pik_assert(Pik *p, PNum e1, PToken *pEq, PNum e2){ |
|
5362
|
char zE1[100], zE2[100], zMsg[300]; |
|
5363
|
|
|
5364
|
/* Convert the numbers to strings using %g for comparison. This |
|
5365
|
** limits the precision of the comparison to account for rounding error. */ |
|
5366
|
snprintf(zE1, sizeof(zE1), "%g", e1); zE1[sizeof(zE1)-1] = 0; |
|
5367
|
snprintf(zE2, sizeof(zE2), "%g", e2); zE1[sizeof(zE2)-1] = 0; |
|
5368
|
if( strcmp(zE1,zE2)!=0 ){ |
|
5369
|
snprintf(zMsg, sizeof(zMsg), "%.50s != %.50s", zE1, zE2); |
|
5370
|
pik_error(p, pEq, zMsg); |
|
5371
|
} |
|
5372
|
return 0; |
|
5373
|
} |
|
5374
|
|
|
5375
|
/* |
|
5376
|
** Process an "assert( place1 == place2 )" statement. Always return NULL. |
|
5377
|
*/ |
|
5378
|
static PObj *pik_position_assert(Pik *p, PPoint *e1, PToken *pEq, PPoint *e2){ |
|
5379
|
char zE1[100], zE2[100], zMsg[210]; |
|
5380
|
|
|
5381
|
/* Convert the numbers to strings using %g for comparison. This |
|
5382
|
** limits the precision of the comparison to account for rounding error. */ |
|
5383
|
snprintf(zE1, sizeof(zE1), "(%g,%g)", e1->x, e1->y); zE1[sizeof(zE1)-1] = 0; |
|
5384
|
snprintf(zE2, sizeof(zE2), "(%g,%g)", e2->x, e2->y); zE1[sizeof(zE2)-1] = 0; |
|
5385
|
if( strcmp(zE1,zE2)!=0 ){ |
|
5386
|
snprintf(zMsg, sizeof(zMsg), "%s != %s", zE1, zE2); |
|
5387
|
pik_error(p, pEq, zMsg); |
|
5388
|
} |
|
5389
|
return 0; |
|
5390
|
} |
|
5391
|
|
|
5392
|
/* Free a complete list of objects */ |
|
5393
|
static void pik_elist_free(Pik *p, PList *pList){ |
|
5394
|
int i; |
|
5395
|
if( pList==0 ) return; |
|
5396
|
for(i=0; i<pList->n; i++){ |
|
5397
|
pik_elem_free(p, pList->a[i]); |
|
5398
|
} |
|
5399
|
free(pList->a); |
|
5400
|
free(pList); |
|
5401
|
return; |
|
5402
|
} |
|
5403
|
|
|
5404
|
/* Free a single object, and its substructure */ |
|
5405
|
static void pik_elem_free(Pik *p, PObj *pObj){ |
|
5406
|
if( pObj==0 ) return; |
|
5407
|
free(pObj->zName); |
|
5408
|
pik_elist_free(p, pObj->pSublist); |
|
5409
|
free(pObj->aPath); |
|
5410
|
free(pObj); |
|
5411
|
} |
|
5412
|
|
|
5413
|
/* Convert a numeric literal into a number. Return that number. |
|
5414
|
** There is no error handling because the tokenizer has already |
|
5415
|
** assured us that the numeric literal is valid. |
|
5416
|
** |
|
5417
|
** Allowed number forms: |
|
5418
|
** |
|
5419
|
** (1) Floating point literal |
|
5420
|
** (2) Same as (1) but followed by a unit: "cm", "mm", "in", |
|
5421
|
** "px", "pt", or "pc". |
|
5422
|
** (3) Hex integers: 0x000000 |
|
5423
|
** |
|
5424
|
** This routine returns the result in inches. If a different unit |
|
5425
|
** is specified, the conversion happens automatically. |
|
5426
|
*/ |
|
5427
|
PNum pik_atof(PToken *num){ |
|
5428
|
char *endptr; |
|
5429
|
PNum ans; |
|
5430
|
if( num->n>=3 && num->z[0]=='0' && (num->z[1]=='x'||num->z[1]=='X') ){ |
|
5431
|
return (PNum)strtol(num->z+2, 0, 16); |
|
5432
|
} |
|
5433
|
ans = strtod(num->z, &endptr); |
|
5434
|
if( (int)(endptr - num->z)==(int)num->n-2 ){ |
|
5435
|
char c1 = endptr[0]; |
|
5436
|
char c2 = endptr[1]; |
|
5437
|
if( c1=='c' && c2=='m' ){ |
|
5438
|
ans /= 2.54; |
|
5439
|
}else if( c1=='m' && c2=='m' ){ |
|
5440
|
ans /= 25.4; |
|
5441
|
}else if( c1=='p' && c2=='x' ){ |
|
5442
|
ans /= 96; |
|
5443
|
}else if( c1=='p' && c2=='t' ){ |
|
5444
|
ans /= 72; |
|
5445
|
}else if( c1=='p' && c2=='c' ){ |
|
5446
|
ans /= 6; |
|
5447
|
} |
|
5448
|
} |
|
5449
|
return ans; |
|
5450
|
} |
|
5451
|
|
|
5452
|
/* |
|
5453
|
** Compute the distance between two points |
|
5454
|
*/ |
|
5455
|
static PNum pik_dist(PPoint *pA, PPoint *pB){ |
|
5456
|
PNum dx, dy; |
|
5457
|
dx = pB->x - pA->x; |
|
5458
|
dy = pB->y - pA->y; |
|
5459
|
return hypot(dx,dy); |
|
5460
|
} |
|
5461
|
|
|
5462
|
/* Return true if a bounding box is empty. |
|
5463
|
*/ |
|
5464
|
static int pik_bbox_isempty(PBox *p){ |
|
5465
|
return p->sw.x>p->ne.x; |
|
5466
|
} |
|
5467
|
|
|
5468
|
/* Return true if point pPt is contained within the bounding box pBox |
|
5469
|
*/ |
|
5470
|
static int pik_bbox_contains_point(PBox *pBox, PPoint *pPt){ |
|
5471
|
if( pik_bbox_isempty(pBox) ) return 0; |
|
5472
|
if( pPt->x < pBox->sw.x ) return 0; |
|
5473
|
if( pPt->x > pBox->ne.x ) return 0; |
|
5474
|
if( pPt->y < pBox->sw.y ) return 0; |
|
5475
|
if( pPt->y > pBox->ne.y ) return 0; |
|
5476
|
return 1; |
|
5477
|
} |
|
5478
|
|
|
5479
|
/* Initialize a bounding box to an empty container |
|
5480
|
*/ |
|
5481
|
static void pik_bbox_init(PBox *p){ |
|
5482
|
p->sw.x = 1.0; |
|
5483
|
p->sw.y = 1.0; |
|
5484
|
p->ne.x = 0.0; |
|
5485
|
p->ne.y = 0.0; |
|
5486
|
} |
|
5487
|
|
|
5488
|
/* Enlarge the PBox of the first argument so that it fully |
|
5489
|
** covers the second PBox |
|
5490
|
*/ |
|
5491
|
static void pik_bbox_addbox(PBox *pA, PBox *pB){ |
|
5492
|
if( pik_bbox_isempty(pA) ){ |
|
5493
|
*pA = *pB; |
|
5494
|
} |
|
5495
|
if( pik_bbox_isempty(pB) ) return; |
|
5496
|
if( pA->sw.x>pB->sw.x ) pA->sw.x = pB->sw.x; |
|
5497
|
if( pA->sw.y>pB->sw.y ) pA->sw.y = pB->sw.y; |
|
5498
|
if( pA->ne.x<pB->ne.x ) pA->ne.x = pB->ne.x; |
|
5499
|
if( pA->ne.y<pB->ne.y ) pA->ne.y = pB->ne.y; |
|
5500
|
} |
|
5501
|
|
|
5502
|
/* Enlarge the PBox of the first argument, if necessary, so that |
|
5503
|
** it contains the point described by the 2nd and 3rd arguments. |
|
5504
|
*/ |
|
5505
|
static void pik_bbox_add_xy(PBox *pA, PNum x, PNum y){ |
|
5506
|
if( pik_bbox_isempty(pA) ){ |
|
5507
|
pA->ne.x = x; |
|
5508
|
pA->ne.y = y; |
|
5509
|
pA->sw.x = x; |
|
5510
|
pA->sw.y = y; |
|
5511
|
return; |
|
5512
|
} |
|
5513
|
if( pA->sw.x>x ) pA->sw.x = x; |
|
5514
|
if( pA->sw.y>y ) pA->sw.y = y; |
|
5515
|
if( pA->ne.x<x ) pA->ne.x = x; |
|
5516
|
if( pA->ne.y<y ) pA->ne.y = y; |
|
5517
|
} |
|
5518
|
|
|
5519
|
/* Enlarge the PBox so that it is able to contain an ellipse |
|
5520
|
** centered at x,y and with radiuses rx and ry. |
|
5521
|
*/ |
|
5522
|
static void pik_bbox_addellipse(PBox *pA, PNum x, PNum y, PNum rx, PNum ry){ |
|
5523
|
if( pik_bbox_isempty(pA) ){ |
|
5524
|
pA->ne.x = x+rx; |
|
5525
|
pA->ne.y = y+ry; |
|
5526
|
pA->sw.x = x-rx; |
|
5527
|
pA->sw.y = y-ry; |
|
5528
|
return; |
|
5529
|
} |
|
5530
|
if( pA->sw.x>x-rx ) pA->sw.x = x-rx; |
|
5531
|
if( pA->sw.y>y-ry ) pA->sw.y = y-ry; |
|
5532
|
if( pA->ne.x<x+rx ) pA->ne.x = x+rx; |
|
5533
|
if( pA->ne.y<y+ry ) pA->ne.y = y+ry; |
|
5534
|
} |
|
5535
|
|
|
5536
|
|
|
5537
|
|
|
5538
|
/* Append a new object onto the end of an object list. The |
|
5539
|
** object list is created if it does not already exist. Return |
|
5540
|
** the new object list. |
|
5541
|
*/ |
|
5542
|
static PList *pik_elist_append(Pik *p, PList *pList, PObj *pObj){ |
|
5543
|
if( pObj==0 ) return pList; |
|
5544
|
if( pList==0 ){ |
|
5545
|
pList = malloc(sizeof(*pList)); |
|
5546
|
if( pList==0 ){ |
|
5547
|
pik_error(p, 0, 0); |
|
5548
|
pik_elem_free(p, pObj); |
|
5549
|
return 0; |
|
5550
|
} |
|
5551
|
memset(pList, 0, sizeof(*pList)); |
|
5552
|
} |
|
5553
|
if( pList->n>=pList->nAlloc ){ |
|
5554
|
int nNew = (pList->n+5)*2; |
|
5555
|
PObj **pNew = realloc(pList->a, sizeof(PObj*)*nNew); |
|
5556
|
if( pNew==0 ){ |
|
5557
|
pik_error(p, 0, 0); |
|
5558
|
pik_elem_free(p, pObj); |
|
5559
|
return pList; |
|
5560
|
} |
|
5561
|
pList->nAlloc = nNew; |
|
5562
|
pList->a = pNew; |
|
5563
|
} |
|
5564
|
pList->a[pList->n++] = pObj; |
|
5565
|
p->list = pList; |
|
5566
|
return pList; |
|
5567
|
} |
|
5568
|
|
|
5569
|
/* Convert an object class name into a PClass pointer |
|
5570
|
*/ |
|
5571
|
static const PClass *pik_find_class(PToken *pId){ |
|
5572
|
int first = 0; |
|
5573
|
int last = count(aClass) - 1; |
|
5574
|
do{ |
|
5575
|
int mid = (first+last)/2; |
|
5576
|
int c = strncmp(aClass[mid].zName, pId->z, pId->n); |
|
5577
|
if( c==0 ){ |
|
5578
|
c = aClass[mid].zName[pId->n]!=0; |
|
5579
|
if( c==0 ) return &aClass[mid]; |
|
5580
|
} |
|
5581
|
if( c<0 ){ |
|
5582
|
first = mid + 1; |
|
5583
|
}else{ |
|
5584
|
last = mid - 1; |
|
5585
|
} |
|
5586
|
}while( first<=last ); |
|
5587
|
return 0; |
|
5588
|
} |
|
5589
|
|
|
5590
|
/* Allocate and return a new PObj object. |
|
5591
|
** |
|
5592
|
** If pId!=0 then pId is an identifier that defines the object class. |
|
5593
|
** If pStr!=0 then it is a STRING literal that defines a text object. |
|
5594
|
** If pSublist!=0 then this is a [...] object. If all three parameters |
|
5595
|
** are NULL then this is a no-op object used to define a PLACENAME. |
|
5596
|
*/ |
|
5597
|
static PObj *pik_elem_new(Pik *p, PToken *pId, PToken *pStr,PList *pSublist){ |
|
5598
|
PObj *pNew; |
|
5599
|
int miss = 0; |
|
5600
|
|
|
5601
|
if( p->nErr ) return 0; |
|
5602
|
pNew = malloc( sizeof(*pNew) ); |
|
5603
|
if( pNew==0 ){ |
|
5604
|
pik_error(p,0,0); |
|
5605
|
pik_elist_free(p, pSublist); |
|
5606
|
return 0; |
|
5607
|
} |
|
5608
|
memset(pNew, 0, sizeof(*pNew)); |
|
5609
|
p->cur = pNew; |
|
5610
|
p->nTPath = 1; |
|
5611
|
p->thenFlag = 0; |
|
5612
|
if( p->list==0 || p->list->n==0 ){ |
|
5613
|
pNew->ptAt.x = pNew->ptAt.y = 0.0; |
|
5614
|
pNew->eWith = CP_C; |
|
5615
|
}else{ |
|
5616
|
PObj *pPrior = p->list->a[p->list->n-1]; |
|
5617
|
pNew->ptAt = pPrior->ptExit; |
|
5618
|
switch( p->eDir ){ |
|
5619
|
default: pNew->eWith = CP_W; break; |
|
5620
|
case DIR_LEFT: pNew->eWith = CP_E; break; |
|
5621
|
case DIR_UP: pNew->eWith = CP_S; break; |
|
5622
|
case DIR_DOWN: pNew->eWith = CP_N; break; |
|
5623
|
} |
|
5624
|
} |
|
5625
|
p->aTPath[0] = pNew->ptAt; |
|
5626
|
pNew->with = pNew->ptAt; |
|
5627
|
pNew->outDir = pNew->inDir = p->eDir; |
|
5628
|
pNew->iLayer = pik_value_int(p, "layer", 5, &miss); |
|
5629
|
if( miss ) pNew->iLayer = 1000; |
|
5630
|
if( pNew->iLayer<0 ) pNew->iLayer = 0; |
|
5631
|
if( pSublist ){ |
|
5632
|
pNew->type = &sublistClass; |
|
5633
|
pNew->pSublist = pSublist; |
|
5634
|
sublistClass.xInit(p,pNew); |
|
5635
|
return pNew; |
|
5636
|
} |
|
5637
|
if( pStr ){ |
|
5638
|
PToken n; |
|
5639
|
n.z = "text"; |
|
5640
|
n.n = 4; |
|
5641
|
pNew->type = pik_find_class(&n); |
|
5642
|
assert( pNew->type!=0 ); |
|
5643
|
pNew->errTok = *pStr; |
|
5644
|
pNew->type->xInit(p, pNew); |
|
5645
|
pik_add_txt(p, pStr, pStr->eCode); |
|
5646
|
return pNew; |
|
5647
|
} |
|
5648
|
if( pId ){ |
|
5649
|
const PClass *pClass; |
|
5650
|
pNew->errTok = *pId; |
|
5651
|
pClass = pik_find_class(pId); |
|
5652
|
if( pClass ){ |
|
5653
|
pNew->type = pClass; |
|
5654
|
pNew->sw = pik_value(p, "thickness",9,0); |
|
5655
|
pNew->fill = pik_value(p, "fill",4,0); |
|
5656
|
pNew->color = pik_value(p, "color",5,0); |
|
5657
|
pClass->xInit(p, pNew); |
|
5658
|
return pNew; |
|
5659
|
} |
|
5660
|
pik_error(p, pId, "unknown object type"); |
|
5661
|
pik_elem_free(p, pNew); |
|
5662
|
return 0; |
|
5663
|
} |
|
5664
|
pNew->type = &noopClass; |
|
5665
|
pNew->ptExit = pNew->ptEnter = pNew->ptAt; |
|
5666
|
return pNew; |
|
5667
|
} |
|
5668
|
|
|
5669
|
/* |
|
5670
|
** If the ID token in the argument is the name of a macro, return |
|
5671
|
** the PMacro object for that macro |
|
5672
|
*/ |
|
5673
|
static PMacro *pik_find_macro(Pik *p, PToken *pId){ |
|
5674
|
PMacro *pMac; |
|
5675
|
for(pMac = p->pMacros; pMac; pMac=pMac->pNext){ |
|
5676
|
if( pMac->macroName.n==pId->n |
|
5677
|
&& strncmp(pMac->macroName.z,pId->z,pId->n)==0 |
|
5678
|
){ |
|
5679
|
return pMac; |
|
5680
|
} |
|
5681
|
} |
|
5682
|
return 0; |
|
5683
|
} |
|
5684
|
|
|
5685
|
/* Add a new macro |
|
5686
|
*/ |
|
5687
|
static void pik_add_macro( |
|
5688
|
Pik *p, /* Current Pikchr diagram */ |
|
5689
|
PToken *pId, /* The ID token that defines the macro name */ |
|
5690
|
PToken *pCode /* Macro body inside of {...} */ |
|
5691
|
){ |
|
5692
|
PMacro *pNew = pik_find_macro(p, pId); |
|
5693
|
if( pNew==0 ){ |
|
5694
|
pNew = malloc( sizeof(*pNew) ); |
|
5695
|
if( pNew==0 ){ |
|
5696
|
pik_error(p, 0, 0); |
|
5697
|
return; |
|
5698
|
} |
|
5699
|
pNew->pNext = p->pMacros; |
|
5700
|
p->pMacros = pNew; |
|
5701
|
pNew->macroName = *pId; |
|
5702
|
} |
|
5703
|
pNew->macroBody.z = pCode->z+1; |
|
5704
|
pNew->macroBody.n = pCode->n-2; |
|
5705
|
pNew->inUse = 0; |
|
5706
|
} |
|
5707
|
|
|
5708
|
|
|
5709
|
/* |
|
5710
|
** Set the output direction and exit point for an object |
|
5711
|
*/ |
|
5712
|
static void pik_elem_set_exit(PObj *pObj, int eDir){ |
|
5713
|
assert( ValidDir(eDir) ); |
|
5714
|
pObj->outDir = eDir; |
|
5715
|
if( !pObj->type->isLine || pObj->bClose ){ |
|
5716
|
pObj->ptExit = pObj->ptAt; |
|
5717
|
switch( pObj->outDir ){ |
|
5718
|
default: pObj->ptExit.x += pObj->w*0.5; break; |
|
5719
|
case DIR_LEFT: pObj->ptExit.x -= pObj->w*0.5; break; |
|
5720
|
case DIR_UP: pObj->ptExit.y += pObj->h*0.5; break; |
|
5721
|
case DIR_DOWN: pObj->ptExit.y -= pObj->h*0.5; break; |
|
5722
|
} |
|
5723
|
} |
|
5724
|
} |
|
5725
|
|
|
5726
|
/* Change the layout direction. |
|
5727
|
*/ |
|
5728
|
static void pik_set_direction(Pik *p, int eDir){ |
|
5729
|
assert( ValidDir(eDir) ); |
|
5730
|
p->eDir = (unsigned char)eDir; |
|
5731
|
|
|
5732
|
/* It seems to make sense to reach back into the last object and |
|
5733
|
** change its exit point (its ".end") to correspond to the new |
|
5734
|
** direction. Things just seem to work better this way. However, |
|
5735
|
** legacy PIC does *not* do this. |
|
5736
|
** |
|
5737
|
** The difference can be seen in a script like this: |
|
5738
|
** |
|
5739
|
** arrow; circle; down; arrow |
|
5740
|
** |
|
5741
|
** You can make pikchr render the above exactly like PIC |
|
5742
|
** by deleting the following three lines. But I (drh) think |
|
5743
|
** it works better with those lines in place. |
|
5744
|
*/ |
|
5745
|
if( p->list && p->list->n ){ |
|
5746
|
pik_elem_set_exit(p->list->a[p->list->n-1], eDir); |
|
5747
|
} |
|
5748
|
} |
|
5749
|
|
|
5750
|
/* Move all coordinates contained within an object (and within its |
|
5751
|
** substructure) by dx, dy |
|
5752
|
*/ |
|
5753
|
static void pik_elem_move(PObj *pObj, PNum dx, PNum dy){ |
|
5754
|
int i; |
|
5755
|
pObj->ptAt.x += dx; |
|
5756
|
pObj->ptAt.y += dy; |
|
5757
|
pObj->ptEnter.x += dx; |
|
5758
|
pObj->ptEnter.y += dy; |
|
5759
|
pObj->ptExit.x += dx; |
|
5760
|
pObj->ptExit.y += dy; |
|
5761
|
pObj->bbox.ne.x += dx; |
|
5762
|
pObj->bbox.ne.y += dy; |
|
5763
|
pObj->bbox.sw.x += dx; |
|
5764
|
pObj->bbox.sw.y += dy; |
|
5765
|
for(i=0; i<pObj->nPath; i++){ |
|
5766
|
pObj->aPath[i].x += dx; |
|
5767
|
pObj->aPath[i].y += dy; |
|
5768
|
} |
|
5769
|
if( pObj->pSublist ){ |
|
5770
|
pik_elist_move(pObj->pSublist, dx, dy); |
|
5771
|
} |
|
5772
|
} |
|
5773
|
static void pik_elist_move(PList *pList, PNum dx, PNum dy){ |
|
5774
|
int i; |
|
5775
|
for(i=0; i<pList->n; i++){ |
|
5776
|
pik_elem_move(pList->a[i], dx, dy); |
|
5777
|
} |
|
5778
|
} |
|
5779
|
|
|
5780
|
/* |
|
5781
|
** Check to see if it is ok to set the value of paraemeter mThis. |
|
5782
|
** Return 0 if it is ok. If it not ok, generate an appropriate |
|
5783
|
** error message and return non-zero. |
|
5784
|
** |
|
5785
|
** Flags are set in pObj so that the same object or conflicting |
|
5786
|
** objects may not be set again. |
|
5787
|
** |
|
5788
|
** To be ok, bit mThis must be clear and no more than one of |
|
5789
|
** the bits identified by mBlockers may be set. |
|
5790
|
*/ |
|
5791
|
static int pik_param_ok( |
|
5792
|
Pik *p, /* For storing the error message (if any) */ |
|
5793
|
PObj *pObj, /* The object under construction */ |
|
5794
|
PToken *pId, /* Make the error point to this token */ |
|
5795
|
int mThis /* Value we are trying to set */ |
|
5796
|
){ |
|
5797
|
if( pObj->mProp & mThis ){ |
|
5798
|
pik_error(p, pId, "value is already set"); |
|
5799
|
return 1; |
|
5800
|
} |
|
5801
|
if( pObj->mCalc & mThis ){ |
|
5802
|
pik_error(p, pId, "value already fixed by prior constraints"); |
|
5803
|
return 1; |
|
5804
|
} |
|
5805
|
pObj->mProp |= mThis; |
|
5806
|
return 0; |
|
5807
|
} |
|
5808
|
|
|
5809
|
|
|
5810
|
/* |
|
5811
|
** Set a numeric property like "width 7" or "radius 200%". |
|
5812
|
** |
|
5813
|
** The rAbs term is an absolute value to add in. rRel is |
|
5814
|
** a relative value by which to change the current value. |
|
5815
|
*/ |
|
5816
|
void pik_set_numprop(Pik *p, PToken *pId, PRel *pVal){ |
|
5817
|
PObj *pObj = p->cur; |
|
5818
|
switch( pId->eType ){ |
|
5819
|
case T_HEIGHT: |
|
5820
|
if( pik_param_ok(p, pObj, pId, A_HEIGHT) ) return; |
|
5821
|
pObj->h = pObj->h*pVal->rRel + pVal->rAbs; |
|
5822
|
break; |
|
5823
|
case T_WIDTH: |
|
5824
|
if( pik_param_ok(p, pObj, pId, A_WIDTH) ) return; |
|
5825
|
pObj->w = pObj->w*pVal->rRel + pVal->rAbs; |
|
5826
|
break; |
|
5827
|
case T_RADIUS: |
|
5828
|
if( pik_param_ok(p, pObj, pId, A_RADIUS) ) return; |
|
5829
|
pObj->rad = pObj->rad*pVal->rRel + pVal->rAbs; |
|
5830
|
break; |
|
5831
|
case T_DIAMETER: |
|
5832
|
if( pik_param_ok(p, pObj, pId, A_RADIUS) ) return; |
|
5833
|
pObj->rad = pObj->rad*pVal->rRel + 0.5*pVal->rAbs; /* diam it 2x rad */ |
|
5834
|
break; |
|
5835
|
case T_THICKNESS: |
|
5836
|
if( pik_param_ok(p, pObj, pId, A_THICKNESS) ) return; |
|
5837
|
pObj->sw = pObj->sw*pVal->rRel + pVal->rAbs; |
|
5838
|
break; |
|
5839
|
} |
|
5840
|
if( pObj->type->xNumProp ){ |
|
5841
|
pObj->type->xNumProp(p, pObj, pId); |
|
5842
|
} |
|
5843
|
return; |
|
5844
|
} |
|
5845
|
|
|
5846
|
/* |
|
5847
|
** Set a color property. The argument is an RGB value. |
|
5848
|
*/ |
|
5849
|
void pik_set_clrprop(Pik *p, PToken *pId, PNum rClr){ |
|
5850
|
PObj *pObj = p->cur; |
|
5851
|
switch( pId->eType ){ |
|
5852
|
case T_FILL: |
|
5853
|
if( pik_param_ok(p, pObj, pId, A_FILL) ) return; |
|
5854
|
pObj->fill = rClr; |
|
5855
|
break; |
|
5856
|
case T_COLOR: |
|
5857
|
if( pik_param_ok(p, pObj, pId, A_COLOR) ) return; |
|
5858
|
pObj->color = rClr; |
|
5859
|
break; |
|
5860
|
} |
|
5861
|
if( pObj->type->xNumProp ){ |
|
5862
|
pObj->type->xNumProp(p, pObj, pId); |
|
5863
|
} |
|
5864
|
return; |
|
5865
|
} |
|
5866
|
|
|
5867
|
/* |
|
5868
|
** Set a "dashed" property like "dash 0.05" |
|
5869
|
** |
|
5870
|
** Use the value supplied by pVal if available. If pVal==0, use |
|
5871
|
** a default. |
|
5872
|
*/ |
|
5873
|
void pik_set_dashed(Pik *p, PToken *pId, PNum *pVal){ |
|
5874
|
PObj *pObj = p->cur; |
|
5875
|
PNum v; |
|
5876
|
switch( pId->eType ){ |
|
5877
|
case T_DOTTED: { |
|
5878
|
v = pVal==0 ? pik_value(p,"dashwid",7,0) : *pVal; |
|
5879
|
pObj->dotted = v; |
|
5880
|
pObj->dashed = 0.0; |
|
5881
|
break; |
|
5882
|
} |
|
5883
|
case T_DASHED: { |
|
5884
|
v = pVal==0 ? pik_value(p,"dashwid",7,0) : *pVal; |
|
5885
|
pObj->dashed = v; |
|
5886
|
pObj->dotted = 0.0; |
|
5887
|
break; |
|
5888
|
} |
|
5889
|
} |
|
5890
|
} |
|
5891
|
|
|
5892
|
/* |
|
5893
|
** If the current path information came from a "same" or "same as" |
|
5894
|
** reset it. |
|
5895
|
*/ |
|
5896
|
static void pik_reset_samepath(Pik *p){ |
|
5897
|
if( p->samePath ){ |
|
5898
|
p->samePath = 0; |
|
5899
|
p->nTPath = 1; |
|
5900
|
} |
|
5901
|
} |
|
5902
|
|
|
5903
|
|
|
5904
|
/* Add a new term to the path for a line-oriented object by transferring |
|
5905
|
** the information in the ptTo field over onto the path and into ptFrom |
|
5906
|
** resetting the ptTo. |
|
5907
|
*/ |
|
5908
|
static void pik_then(Pik *p, PToken *pToken, PObj *pObj){ |
|
5909
|
int n; |
|
5910
|
if( !pObj->type->isLine ){ |
|
5911
|
pik_error(p, pToken, "use with line-oriented objects only"); |
|
5912
|
return; |
|
5913
|
} |
|
5914
|
n = p->nTPath - 1; |
|
5915
|
if( n<1 && (pObj->mProp & A_FROM)==0 ){ |
|
5916
|
pik_error(p, pToken, "no prior path points"); |
|
5917
|
return; |
|
5918
|
} |
|
5919
|
p->thenFlag = 1; |
|
5920
|
} |
|
5921
|
|
|
5922
|
/* Advance to the next entry in p->aTPath. Return its index. |
|
5923
|
*/ |
|
5924
|
static int pik_next_rpath(Pik *p, PToken *pErr){ |
|
5925
|
int n = p->nTPath - 1; |
|
5926
|
if( n+1>=(int)count(p->aTPath) ){ |
|
5927
|
pik_error(0, pErr, "too many path elements"); |
|
5928
|
return n; |
|
5929
|
} |
|
5930
|
n++; |
|
5931
|
p->nTPath++; |
|
5932
|
p->aTPath[n] = p->aTPath[n-1]; |
|
5933
|
p->mTPath = 0; |
|
5934
|
return n; |
|
5935
|
} |
|
5936
|
|
|
5937
|
/* Add a direction term to an object. "up 0.5", or "left 3", or "down" |
|
5938
|
** or "down 50%". |
|
5939
|
*/ |
|
5940
|
static void pik_add_direction(Pik *p, PToken *pDir, PRel *pVal){ |
|
5941
|
PObj *pObj = p->cur; |
|
5942
|
int n; |
|
5943
|
int dir; |
|
5944
|
if( !pObj->type->isLine ){ |
|
5945
|
if( pDir ){ |
|
5946
|
pik_error(p, pDir, "use with line-oriented objects only"); |
|
5947
|
}else{ |
|
5948
|
PToken x = pik_next_semantic_token(&pObj->errTok); |
|
5949
|
pik_error(p, &x, "syntax error"); |
|
5950
|
} |
|
5951
|
return; |
|
5952
|
} |
|
5953
|
pik_reset_samepath(p); |
|
5954
|
n = p->nTPath - 1; |
|
5955
|
if( p->thenFlag || p->mTPath==3 || n==0 ){ |
|
5956
|
n = pik_next_rpath(p, pDir); |
|
5957
|
p->thenFlag = 0; |
|
5958
|
} |
|
5959
|
dir = pDir ? pDir->eCode : p->eDir; |
|
5960
|
switch( dir ){ |
|
5961
|
case DIR_UP: |
|
5962
|
if( p->mTPath & 2 ) n = pik_next_rpath(p, pDir); |
|
5963
|
p->aTPath[n].y += pVal->rAbs + pObj->h*pVal->rRel; |
|
5964
|
p->mTPath |= 2; |
|
5965
|
break; |
|
5966
|
case DIR_DOWN: |
|
5967
|
if( p->mTPath & 2 ) n = pik_next_rpath(p, pDir); |
|
5968
|
p->aTPath[n].y -= pVal->rAbs + pObj->h*pVal->rRel; |
|
5969
|
p->mTPath |= 2; |
|
5970
|
break; |
|
5971
|
case DIR_RIGHT: |
|
5972
|
if( p->mTPath & 1 ) n = pik_next_rpath(p, pDir); |
|
5973
|
p->aTPath[n].x += pVal->rAbs + pObj->w*pVal->rRel; |
|
5974
|
p->mTPath |= 1; |
|
5975
|
break; |
|
5976
|
case DIR_LEFT: |
|
5977
|
if( p->mTPath & 1 ) n = pik_next_rpath(p, pDir); |
|
5978
|
p->aTPath[n].x -= pVal->rAbs + pObj->w*pVal->rRel; |
|
5979
|
p->mTPath |= 1; |
|
5980
|
break; |
|
5981
|
} |
|
5982
|
pObj->outDir = dir; |
|
5983
|
} |
|
5984
|
|
|
5985
|
/* Process a movement attribute of one of these forms: |
|
5986
|
** |
|
5987
|
** pDist pHdgKW rHdg pEdgept |
|
5988
|
** GO distance HEADING angle |
|
5989
|
** GO distance compasspoint |
|
5990
|
*/ |
|
5991
|
static void pik_move_hdg( |
|
5992
|
Pik *p, /* The Pikchr context */ |
|
5993
|
PRel *pDist, /* Distance to move */ |
|
5994
|
PToken *pHeading, /* "heading" keyword if present */ |
|
5995
|
PNum rHdg, /* Angle argument to "heading" keyword */ |
|
5996
|
PToken *pEdgept, /* EDGEPT keyword "ne", "sw", etc... */ |
|
5997
|
PToken *pErr /* Token to use for error messages */ |
|
5998
|
){ |
|
5999
|
PObj *pObj = p->cur; |
|
6000
|
int n; |
|
6001
|
PNum rDist = pDist->rAbs + pik_value(p,"linewid",7,0)*pDist->rRel; |
|
6002
|
if( !pObj->type->isLine ){ |
|
6003
|
pik_error(p, pErr, "use with line-oriented objects only"); |
|
6004
|
return; |
|
6005
|
} |
|
6006
|
pik_reset_samepath(p); |
|
6007
|
do{ |
|
6008
|
n = pik_next_rpath(p, pErr); |
|
6009
|
}while( n<1 ); |
|
6010
|
if( pHeading ){ |
|
6011
|
rHdg = fmod(rHdg,360.0); |
|
6012
|
}else if( pEdgept->eEdge==CP_C ){ |
|
6013
|
pik_error(p, pEdgept, "syntax error"); |
|
6014
|
return; |
|
6015
|
}else{ |
|
6016
|
rHdg = pik_hdg_angle[pEdgept->eEdge]; |
|
6017
|
} |
|
6018
|
if( rHdg<=45.0 ){ |
|
6019
|
pObj->outDir = DIR_UP; |
|
6020
|
}else if( rHdg<=135.0 ){ |
|
6021
|
pObj->outDir = DIR_RIGHT; |
|
6022
|
}else if( rHdg<=225.0 ){ |
|
6023
|
pObj->outDir = DIR_DOWN; |
|
6024
|
}else if( rHdg<=315.0 ){ |
|
6025
|
pObj->outDir = DIR_LEFT; |
|
6026
|
}else{ |
|
6027
|
pObj->outDir = DIR_UP; |
|
6028
|
} |
|
6029
|
rHdg *= 0.017453292519943295769; /* degrees to radians */ |
|
6030
|
p->aTPath[n].x += rDist*sin(rHdg); |
|
6031
|
p->aTPath[n].y += rDist*cos(rHdg); |
|
6032
|
p->mTPath = 2; |
|
6033
|
} |
|
6034
|
|
|
6035
|
|
|
6036
|
/* Process a movement attribute of the form "right until even with ..." |
|
6037
|
** |
|
6038
|
** pDir is the first keyword, "right" or "left" or "up" or "down". |
|
6039
|
** The movement is in that direction until its closest approach to |
|
6040
|
** the point specified by pPoint. |
|
6041
|
*/ |
|
6042
|
static void pik_evenwith(Pik *p, PToken *pDir, PPoint *pPlace){ |
|
6043
|
PObj *pObj = p->cur; |
|
6044
|
int n; |
|
6045
|
if( !pObj->type->isLine ){ |
|
6046
|
pik_error(p, pDir, "use with line-oriented objects only"); |
|
6047
|
return; |
|
6048
|
} |
|
6049
|
pik_reset_samepath(p); |
|
6050
|
n = p->nTPath - 1; |
|
6051
|
if( p->thenFlag || p->mTPath==3 || n==0 ){ |
|
6052
|
n = pik_next_rpath(p, pDir); |
|
6053
|
p->thenFlag = 0; |
|
6054
|
} |
|
6055
|
switch( pDir->eCode ){ |
|
6056
|
case DIR_DOWN: |
|
6057
|
case DIR_UP: |
|
6058
|
if( p->mTPath & 2 ) n = pik_next_rpath(p, pDir); |
|
6059
|
p->aTPath[n].y = pPlace->y; |
|
6060
|
p->mTPath |= 2; |
|
6061
|
break; |
|
6062
|
case DIR_RIGHT: |
|
6063
|
case DIR_LEFT: |
|
6064
|
if( p->mTPath & 1 ) n = pik_next_rpath(p, pDir); |
|
6065
|
p->aTPath[n].x = pPlace->x; |
|
6066
|
p->mTPath |= 1; |
|
6067
|
break; |
|
6068
|
} |
|
6069
|
pObj->outDir = pDir->eCode; |
|
6070
|
} |
|
6071
|
|
|
6072
|
/* If the last referenced object is centered at point pPt then return |
|
6073
|
** a pointer to that object. If there is no prior object reference, |
|
6074
|
** or if the points are not the same, return NULL. |
|
6075
|
** |
|
6076
|
** This is a side-channel hack used to find the objects at which a |
|
6077
|
** line begins and ends. For example, in |
|
6078
|
** |
|
6079
|
** arrow from OBJ1 to OBJ2 chop |
|
6080
|
** |
|
6081
|
** The arrow object is normally just handed the coordinates of the |
|
6082
|
** centers for OBJ1 and OBJ2. But we also want to know the specific |
|
6083
|
** object named in case there are multiple objects centered at the |
|
6084
|
** same point. |
|
6085
|
** |
|
6086
|
** See forum post 1d46e3a0bc |
|
6087
|
*/ |
|
6088
|
static PObj *pik_last_ref_object(Pik *p, PPoint *pPt){ |
|
6089
|
PObj *pRes = 0; |
|
6090
|
if( p->lastRef==0 ) return 0; |
|
6091
|
if( p->lastRef->ptAt.x==pPt->x |
|
6092
|
&& p->lastRef->ptAt.y==pPt->y |
|
6093
|
){ |
|
6094
|
pRes = p->lastRef; |
|
6095
|
} |
|
6096
|
p->lastRef = 0; |
|
6097
|
return pRes; |
|
6098
|
} |
|
6099
|
|
|
6100
|
/* Set the "from" of an object |
|
6101
|
*/ |
|
6102
|
static void pik_set_from(Pik *p, PObj *pObj, PToken *pTk, PPoint *pPt){ |
|
6103
|
if( !pObj->type->isLine ){ |
|
6104
|
pik_error(p, pTk, "use \"at\" to position this object"); |
|
6105
|
return; |
|
6106
|
} |
|
6107
|
if( pObj->mProp & A_FROM ){ |
|
6108
|
pik_error(p, pTk, "line start location already fixed"); |
|
6109
|
return; |
|
6110
|
} |
|
6111
|
if( pObj->bClose ){ |
|
6112
|
pik_error(p, pTk, "polygon is closed"); |
|
6113
|
return; |
|
6114
|
} |
|
6115
|
if( p->nTPath>1 ){ |
|
6116
|
PNum dx = pPt->x - p->aTPath[0].x; |
|
6117
|
PNum dy = pPt->y - p->aTPath[0].y; |
|
6118
|
int i; |
|
6119
|
for(i=1; i<p->nTPath; i++){ |
|
6120
|
p->aTPath[i].x += dx; |
|
6121
|
p->aTPath[i].y += dy; |
|
6122
|
} |
|
6123
|
} |
|
6124
|
p->aTPath[0] = *pPt; |
|
6125
|
p->mTPath = 3; |
|
6126
|
pObj->mProp |= A_FROM; |
|
6127
|
pObj->pFrom = pik_last_ref_object(p, pPt); |
|
6128
|
} |
|
6129
|
|
|
6130
|
/* Set the "to" of an object |
|
6131
|
*/ |
|
6132
|
static void pik_add_to(Pik *p, PObj *pObj, PToken *pTk, PPoint *pPt){ |
|
6133
|
int n = p->nTPath-1; |
|
6134
|
if( !pObj->type->isLine ){ |
|
6135
|
pik_error(p, pTk, "use \"at\" to position this object"); |
|
6136
|
return; |
|
6137
|
} |
|
6138
|
if( pObj->bClose ){ |
|
6139
|
pik_error(p, pTk, "polygon is closed"); |
|
6140
|
return; |
|
6141
|
} |
|
6142
|
pik_reset_samepath(p); |
|
6143
|
if( n==0 || p->mTPath==3 || p->thenFlag ){ |
|
6144
|
n = pik_next_rpath(p, pTk); |
|
6145
|
} |
|
6146
|
p->aTPath[n] = *pPt; |
|
6147
|
p->mTPath = 3; |
|
6148
|
pObj->pTo = pik_last_ref_object(p, pPt); |
|
6149
|
} |
|
6150
|
|
|
6151
|
static void pik_close_path(Pik *p, PToken *pErr){ |
|
6152
|
PObj *pObj = p->cur; |
|
6153
|
if( p->nTPath<3 ){ |
|
6154
|
pik_error(p, pErr, |
|
6155
|
"need at least 3 vertexes in order to close the polygon"); |
|
6156
|
return; |
|
6157
|
} |
|
6158
|
if( pObj->bClose ){ |
|
6159
|
pik_error(p, pErr, "polygon already closed"); |
|
6160
|
return; |
|
6161
|
} |
|
6162
|
pObj->bClose = 1; |
|
6163
|
} |
|
6164
|
|
|
6165
|
/* Lower the layer of the current object so that it is behind the |
|
6166
|
** given object. |
|
6167
|
*/ |
|
6168
|
static void pik_behind(Pik *p, PObj *pOther){ |
|
6169
|
PObj *pObj = p->cur; |
|
6170
|
if( p->nErr==0 && pObj->iLayer>=pOther->iLayer ){ |
|
6171
|
pObj->iLayer = pOther->iLayer - 1; |
|
6172
|
} |
|
6173
|
} |
|
6174
|
|
|
6175
|
|
|
6176
|
/* Set the "at" of an object |
|
6177
|
*/ |
|
6178
|
static void pik_set_at(Pik *p, PToken *pEdge, PPoint *pAt, PToken *pErrTok){ |
|
6179
|
PObj *pObj; |
|
6180
|
static unsigned char eDirToCp[] = { CP_E, CP_S, CP_W, CP_N }; |
|
6181
|
if( p->nErr ) return; |
|
6182
|
pObj = p->cur; |
|
6183
|
|
|
6184
|
if( pObj->type->isLine ){ |
|
6185
|
pik_error(p, pErrTok, "use \"from\" and \"to\" to position this object"); |
|
6186
|
return; |
|
6187
|
} |
|
6188
|
if( pObj->mProp & A_AT ){ |
|
6189
|
pik_error(p, pErrTok, "location fixed by prior \"at\""); |
|
6190
|
return; |
|
6191
|
} |
|
6192
|
pObj->mProp |= A_AT; |
|
6193
|
pObj->eWith = pEdge ? pEdge->eEdge : CP_C; |
|
6194
|
if( pObj->eWith>=CP_END ){ |
|
6195
|
int dir = pObj->eWith==CP_END ? pObj->outDir : (pObj->inDir+2)%4; |
|
6196
|
pObj->eWith = eDirToCp[dir]; |
|
6197
|
} |
|
6198
|
pObj->with = *pAt; |
|
6199
|
} |
|
6200
|
|
|
6201
|
/* |
|
6202
|
** Try to add a text attribute to an object |
|
6203
|
*/ |
|
6204
|
static void pik_add_txt(Pik *p, PToken *pTxt, int iPos){ |
|
6205
|
PObj *pObj = p->cur; |
|
6206
|
PToken *pT; |
|
6207
|
if( pObj->nTxt >= count(pObj->aTxt) ){ |
|
6208
|
pik_error(p, pTxt, "too many text terms"); |
|
6209
|
return; |
|
6210
|
} |
|
6211
|
pT = &pObj->aTxt[pObj->nTxt++]; |
|
6212
|
*pT = *pTxt; |
|
6213
|
pT->eCode = (short)iPos; |
|
6214
|
} |
|
6215
|
|
|
6216
|
/* Merge "text-position" flags |
|
6217
|
*/ |
|
6218
|
static int pik_text_position(int iPrev, PToken *pFlag){ |
|
6219
|
int iRes = iPrev; |
|
6220
|
switch( pFlag->eType ){ |
|
6221
|
case T_LJUST: iRes = (iRes&~TP_JMASK) | TP_LJUST; break; |
|
6222
|
case T_RJUST: iRes = (iRes&~TP_JMASK) | TP_RJUST; break; |
|
6223
|
case T_ABOVE: iRes = (iRes&~TP_VMASK) | TP_ABOVE; break; |
|
6224
|
case T_CENTER: iRes = (iRes&~TP_VMASK) | TP_CENTER; break; |
|
6225
|
case T_BELOW: iRes = (iRes&~TP_VMASK) | TP_BELOW; break; |
|
6226
|
case T_ITALIC: iRes |= TP_ITALIC; break; |
|
6227
|
case T_BOLD: iRes |= TP_BOLD; break; |
|
6228
|
case T_MONO: iRes |= TP_MONO; break; |
|
6229
|
case T_ALIGNED: iRes |= TP_ALIGN; break; |
|
6230
|
case T_BIG: if( iRes & TP_BIG ) iRes |= TP_XTRA; |
|
6231
|
else iRes = (iRes &~TP_SZMASK)|TP_BIG; break; |
|
6232
|
case T_SMALL: if( iRes & TP_SMALL ) iRes |= TP_XTRA; |
|
6233
|
else iRes = (iRes &~TP_SZMASK)|TP_SMALL; break; |
|
6234
|
} |
|
6235
|
return iRes; |
|
6236
|
} |
|
6237
|
|
|
6238
|
/* |
|
6239
|
** Table of scale-factor estimates for variable-width characters. |
|
6240
|
** Actual character widths vary by font. These numbers are only |
|
6241
|
** guesses. And this table only provides data for ASCII. |
|
6242
|
** |
|
6243
|
** 100 means normal width. |
|
6244
|
*/ |
|
6245
|
static const unsigned char awChar[] = { |
|
6246
|
/* Skip initial 32 control characters */ |
|
6247
|
/* ' ' */ 45, |
|
6248
|
/* '!' */ 55, |
|
6249
|
/* '"' */ 62, |
|
6250
|
/* '#' */ 115, |
|
6251
|
/* '$' */ 90, |
|
6252
|
/* '%' */ 132, |
|
6253
|
/* '&' */ 125, |
|
6254
|
/* '\''*/ 40, |
|
6255
|
|
|
6256
|
/* '(' */ 55, |
|
6257
|
/* ')' */ 55, |
|
6258
|
/* '*' */ 71, |
|
6259
|
/* '+' */ 115, |
|
6260
|
/* ',' */ 45, |
|
6261
|
/* '-' */ 48, |
|
6262
|
/* '.' */ 45, |
|
6263
|
/* '/' */ 50, |
|
6264
|
|
|
6265
|
/* '0' */ 91, |
|
6266
|
/* '1' */ 91, |
|
6267
|
/* '2' */ 91, |
|
6268
|
/* '3' */ 91, |
|
6269
|
/* '4' */ 91, |
|
6270
|
/* '5' */ 91, |
|
6271
|
/* '6' */ 91, |
|
6272
|
/* '7' */ 91, |
|
6273
|
|
|
6274
|
/* '8' */ 91, |
|
6275
|
/* '9' */ 91, |
|
6276
|
/* ':' */ 50, |
|
6277
|
/* ';' */ 50, |
|
6278
|
/* '<' */ 120, |
|
6279
|
/* '=' */ 120, |
|
6280
|
/* '>' */ 120, |
|
6281
|
/* '?' */ 78, |
|
6282
|
|
|
6283
|
/* '@' */ 142, |
|
6284
|
/* 'A' */ 102, |
|
6285
|
/* 'B' */ 105, |
|
6286
|
/* 'C' */ 110, |
|
6287
|
/* 'D' */ 115, |
|
6288
|
/* 'E' */ 105, |
|
6289
|
/* 'F' */ 98, |
|
6290
|
/* 'G' */ 105, |
|
6291
|
|
|
6292
|
/* 'H' */ 125, |
|
6293
|
/* 'I' */ 58, |
|
6294
|
/* 'J' */ 58, |
|
6295
|
/* 'K' */ 107, |
|
6296
|
/* 'L' */ 95, |
|
6297
|
/* 'M' */ 145, |
|
6298
|
/* 'N' */ 125, |
|
6299
|
/* 'O' */ 115, |
|
6300
|
|
|
6301
|
/* 'P' */ 95, |
|
6302
|
/* 'Q' */ 115, |
|
6303
|
/* 'R' */ 107, |
|
6304
|
/* 'S' */ 95, |
|
6305
|
/* 'T' */ 97, |
|
6306
|
/* 'U' */ 118, |
|
6307
|
/* 'V' */ 102, |
|
6308
|
/* 'W' */ 150, |
|
6309
|
|
|
6310
|
/* 'X' */ 100, |
|
6311
|
/* 'Y' */ 93, |
|
6312
|
/* 'Z' */ 100, |
|
6313
|
/* '[' */ 58, |
|
6314
|
/* '\\'*/ 50, |
|
6315
|
/* ']' */ 58, |
|
6316
|
/* '^' */ 119, |
|
6317
|
/* '_' */ 72, |
|
6318
|
|
|
6319
|
/* '`' */ 72, |
|
6320
|
/* 'a' */ 86, |
|
6321
|
/* 'b' */ 92, |
|
6322
|
/* 'c' */ 80, |
|
6323
|
/* 'd' */ 92, |
|
6324
|
/* 'e' */ 85, |
|
6325
|
/* 'f' */ 52, |
|
6326
|
/* 'g' */ 92, |
|
6327
|
|
|
6328
|
/* 'h' */ 92, |
|
6329
|
/* 'i' */ 47, |
|
6330
|
/* 'j' */ 47, |
|
6331
|
/* 'k' */ 88, |
|
6332
|
/* 'l' */ 48, |
|
6333
|
/* 'm' */ 135, |
|
6334
|
/* 'n' */ 92, |
|
6335
|
/* 'o' */ 86, |
|
6336
|
|
|
6337
|
/* 'p' */ 92, |
|
6338
|
/* 'q' */ 92, |
|
6339
|
/* 'r' */ 69, |
|
6340
|
/* 's' */ 75, |
|
6341
|
/* 't' */ 58, |
|
6342
|
/* 'u' */ 92, |
|
6343
|
/* 'v' */ 80, |
|
6344
|
/* 'w' */ 121, |
|
6345
|
|
|
6346
|
/* 'x' */ 81, |
|
6347
|
/* 'y' */ 80, |
|
6348
|
/* 'z' */ 76, |
|
6349
|
/* '{' */ 91, |
|
6350
|
/* '|'*/ 49, |
|
6351
|
/* '}' */ 91, |
|
6352
|
/* '~' */ 118, |
|
6353
|
}; |
|
6354
|
|
|
6355
|
/* Return an estimate of the width of the displayed characters |
|
6356
|
** in a character string. The returned value is 100 times the |
|
6357
|
** average character width. |
|
6358
|
** |
|
6359
|
** Omit "\" used to escape characters. And count entities like |
|
6360
|
** "<" as a single character. Multi-byte UTF8 characters count |
|
6361
|
** as a single character. |
|
6362
|
** |
|
6363
|
** Unless using a monospaced font, attempt to scale the answer by |
|
6364
|
** the actual characters seen. Wide characters count more than |
|
6365
|
** narrow characters. But the widths are only guesses. |
|
6366
|
** |
|
6367
|
*/ |
|
6368
|
static int pik_text_length(const PToken *pToken, const int isMonospace){ |
|
6369
|
const int stdAvg=100, monoAvg=82; |
|
6370
|
int n = pToken->n; |
|
6371
|
const char *z = pToken->z; |
|
6372
|
int cnt, j; |
|
6373
|
for(j=1, cnt=0; j<n-1; j++){ |
|
6374
|
char c = z[j]; |
|
6375
|
if( c=='\\' && z[j+1]!='&' ){ |
|
6376
|
c = z[++j]; |
|
6377
|
}else if( c=='&' ){ |
|
6378
|
int k; |
|
6379
|
for(k=j+1; k<j+7 && z[k]!=0 && z[k]!=';'; k++){} |
|
6380
|
if( z[k]==';' ) j = k; |
|
6381
|
cnt += (isMonospace ? monoAvg : stdAvg) * 3 / 2; |
|
6382
|
continue; |
|
6383
|
} |
|
6384
|
if( (c & 0xc0)==0xc0 ){ |
|
6385
|
while( j+1<n-1 && (z[j+1]&0xc0)==0x80 ){ j++; } |
|
6386
|
cnt += isMonospace ? monoAvg : stdAvg; |
|
6387
|
continue; |
|
6388
|
} |
|
6389
|
if( isMonospace ){ |
|
6390
|
cnt += monoAvg; |
|
6391
|
}else if( c >= 0x20 && c <= 0x7e ){ |
|
6392
|
cnt += awChar[c-0x20]; |
|
6393
|
}else{ |
|
6394
|
cnt += stdAvg; |
|
6395
|
} |
|
6396
|
} |
|
6397
|
return cnt; |
|
6398
|
} |
|
6399
|
|
|
6400
|
/* Adjust the width, height, and/or radius of the object so that |
|
6401
|
** it fits around the text that has been added so far. |
|
6402
|
** |
|
6403
|
** (1) Only text specified prior to this attribute is considered. |
|
6404
|
** (2) The text size is estimated based on the charht and charwid |
|
6405
|
** variable settings. |
|
6406
|
** (3) The fitted attributes can be changed again after this |
|
6407
|
** attribute, for example using "width 110%" if this auto-fit |
|
6408
|
** underestimates the text size. |
|
6409
|
** (4) Previously set attributes will not be altered. In other words, |
|
6410
|
** "width 1in fit" might cause the height to change, but the |
|
6411
|
** width is now set. |
|
6412
|
** (5) This only works for attributes that have an xFit method. |
|
6413
|
** |
|
6414
|
** The eWhich parameter is: |
|
6415
|
** |
|
6416
|
** 1: Fit horizontally only |
|
6417
|
** 2: Fit vertically only |
|
6418
|
** 3: Fit both ways |
|
6419
|
*/ |
|
6420
|
static void pik_size_to_fit(Pik *p, PObj *pObj, PToken *pFit, int eWhich){ |
|
6421
|
PNum w, h; |
|
6422
|
PBox bbox; |
|
6423
|
if( p->nErr ) return; |
|
6424
|
if( pObj==0 ) pObj = p->cur; |
|
6425
|
|
|
6426
|
if( pObj->nTxt==0 ){ |
|
6427
|
pik_error(0, pFit, "no text to fit to"); |
|
6428
|
return; |
|
6429
|
} |
|
6430
|
if( pObj->type->xFit==0 ) return; |
|
6431
|
pik_bbox_init(&bbox); |
|
6432
|
pik_compute_layout_settings(p); |
|
6433
|
pik_append_txt(p, pObj, &bbox); |
|
6434
|
if( (eWhich & 1)!=0 || pObj->bAltAutoFit ){ |
|
6435
|
w = (bbox.ne.x - bbox.sw.x) + p->charWidth; |
|
6436
|
}else{ |
|
6437
|
w = 0; |
|
6438
|
} |
|
6439
|
if( (eWhich & 2)!=0 || pObj->bAltAutoFit ){ |
|
6440
|
PNum h1, h2; |
|
6441
|
h1 = (bbox.ne.y - pObj->ptAt.y); |
|
6442
|
h2 = (pObj->ptAt.y - bbox.sw.y); |
|
6443
|
h = 2.0*( h1<h2 ? h2 : h1 ) + 0.5*p->charHeight; |
|
6444
|
}else{ |
|
6445
|
h = 0; |
|
6446
|
} |
|
6447
|
pObj->type->xFit(p, pObj, w, h); |
|
6448
|
pObj->mProp |= A_FIT; |
|
6449
|
} |
|
6450
|
|
|
6451
|
/* Set a local variable name to "val". |
|
6452
|
** |
|
6453
|
** The name might be a built-in variable or a color name. In either case, |
|
6454
|
** a new application-defined variable is set. Since app-defined variables |
|
6455
|
** are searched first, this will override any built-in variables. |
|
6456
|
*/ |
|
6457
|
static void pik_set_var(Pik *p, PToken *pId, PNum val, PToken *pOp){ |
|
6458
|
PVar *pVar = p->pVar; |
|
6459
|
while( pVar ){ |
|
6460
|
if( pik_token_eq(pId,pVar->zName)==0 ) break; |
|
6461
|
pVar = pVar->pNext; |
|
6462
|
} |
|
6463
|
if( pVar==0 ){ |
|
6464
|
char *z; |
|
6465
|
pVar = malloc( pId->n+1 + sizeof(*pVar) ); |
|
6466
|
if( pVar==0 ){ |
|
6467
|
pik_error(p, 0, 0); |
|
6468
|
return; |
|
6469
|
} |
|
6470
|
pVar->zName = z = (char*)&pVar[1]; |
|
6471
|
memcpy(z, pId->z, pId->n); |
|
6472
|
z[pId->n] = 0; |
|
6473
|
pVar->pNext = p->pVar; |
|
6474
|
pVar->val = pik_value(p, pId->z, pId->n, 0); |
|
6475
|
p->pVar = pVar; |
|
6476
|
} |
|
6477
|
switch( pOp->eCode ){ |
|
6478
|
case T_PLUS: pVar->val += val; break; |
|
6479
|
case T_STAR: pVar->val *= val; break; |
|
6480
|
case T_MINUS: pVar->val -= val; break; |
|
6481
|
case T_SLASH: |
|
6482
|
if( val==0.0 ){ |
|
6483
|
pik_error(p, pOp, "division by zero"); |
|
6484
|
}else{ |
|
6485
|
pVar->val /= val; |
|
6486
|
} |
|
6487
|
break; |
|
6488
|
default: pVar->val = val; break; |
|
6489
|
} |
|
6490
|
p->bLayoutVars = 0; /* Clear the layout setting cache */ |
|
6491
|
} |
|
6492
|
|
|
6493
|
/* |
|
6494
|
** Round a PNum into the nearest integer |
|
6495
|
*/ |
|
6496
|
static int pik_round(PNum v){ |
|
6497
|
if( isnan(v) ) return 0; |
|
6498
|
if( v < -2147483647 ) return (-2147483647-1); |
|
6499
|
if( v >= 2147483647 ) return 2147483647; |
|
6500
|
return (int)v; |
|
6501
|
} |
|
6502
|
|
|
6503
|
/* |
|
6504
|
** Search for the variable named z[0..n-1] in: |
|
6505
|
** |
|
6506
|
** * Application defined variables |
|
6507
|
** * Built-in variables |
|
6508
|
** |
|
6509
|
** Return the value of the variable if found. If not found |
|
6510
|
** return 0.0. Also if pMiss is not NULL, then set it to 1 |
|
6511
|
** if not found. |
|
6512
|
** |
|
6513
|
** This routine is a subroutine to pik_get_var(). But it is also |
|
6514
|
** used by object implementations to look up (possibly overwritten) |
|
6515
|
** values for built-in variables like "boxwid". |
|
6516
|
*/ |
|
6517
|
static PNum pik_value(Pik *p, const char *z, int n, int *pMiss){ |
|
6518
|
PVar *pVar; |
|
6519
|
int first, last, mid, c; |
|
6520
|
for(pVar=p->pVar; pVar; pVar=pVar->pNext){ |
|
6521
|
if( strncmp(pVar->zName,z,n)==0 && pVar->zName[n]==0 ){ |
|
6522
|
return pVar->val; |
|
6523
|
} |
|
6524
|
} |
|
6525
|
first = 0; |
|
6526
|
last = count(aBuiltin)-1; |
|
6527
|
while( first<=last ){ |
|
6528
|
mid = (first+last)/2; |
|
6529
|
c = strncmp(z,aBuiltin[mid].zName,n); |
|
6530
|
if( c==0 && aBuiltin[mid].zName[n] ) c = 1; |
|
6531
|
if( c==0 ) return aBuiltin[mid].val; |
|
6532
|
if( c>0 ){ |
|
6533
|
first = mid+1; |
|
6534
|
}else{ |
|
6535
|
last = mid-1; |
|
6536
|
} |
|
6537
|
} |
|
6538
|
if( pMiss ) *pMiss = 1; |
|
6539
|
return 0.0; |
|
6540
|
} |
|
6541
|
static int pik_value_int(Pik *p, const char *z, int n, int *pMiss){ |
|
6542
|
return pik_round(pik_value(p,z,n,pMiss)); |
|
6543
|
} |
|
6544
|
|
|
6545
|
/* |
|
6546
|
** Look up a color-name. Unlike other names in this program, the |
|
6547
|
** color-names are not case sensitive. So "DarkBlue" and "darkblue" |
|
6548
|
** and "DARKBLUE" all find the same value (139). |
|
6549
|
** |
|
6550
|
** If not found, return -99.0. Also post an error if p!=NULL. |
|
6551
|
** |
|
6552
|
** Special color names "None" and "Off" return -1.0 without causing |
|
6553
|
** an error. |
|
6554
|
*/ |
|
6555
|
static PNum pik_lookup_color(Pik *p, PToken *pId){ |
|
6556
|
int first, last, mid, c = 0; |
|
6557
|
first = 0; |
|
6558
|
last = count(aColor)-1; |
|
6559
|
while( first<=last ){ |
|
6560
|
const char *zClr; |
|
6561
|
int c1, c2; |
|
6562
|
unsigned int i; |
|
6563
|
mid = (first+last)/2; |
|
6564
|
zClr = aColor[mid].zName; |
|
6565
|
for(i=0; i<pId->n; i++){ |
|
6566
|
c1 = zClr[i]&0x7f; |
|
6567
|
if( IsUpper(c1) ) c1 = ToLower(c1); |
|
6568
|
c2 = pId->z[i]&0x7f; |
|
6569
|
if( IsUpper(c2) ) c2 = ToLower(c2); |
|
6570
|
c = c2 - c1; |
|
6571
|
if( c ) break; |
|
6572
|
} |
|
6573
|
if( c==0 && aColor[mid].zName[pId->n] ) c = -1; |
|
6574
|
if( c==0 ) return (double)aColor[mid].val; |
|
6575
|
if( c>0 ){ |
|
6576
|
first = mid+1; |
|
6577
|
}else{ |
|
6578
|
last = mid-1; |
|
6579
|
} |
|
6580
|
} |
|
6581
|
if( p ) pik_error(p, pId, "not a known color name"); |
|
6582
|
return -99.0; |
|
6583
|
} |
|
6584
|
|
|
6585
|
/* Get the value of a variable. |
|
6586
|
** |
|
6587
|
** Search in order: |
|
6588
|
** |
|
6589
|
** * Application defined variables |
|
6590
|
** * Built-in variables |
|
6591
|
** * Color names |
|
6592
|
** |
|
6593
|
** If no such variable is found, throw an error. |
|
6594
|
*/ |
|
6595
|
static PNum pik_get_var(Pik *p, PToken *pId){ |
|
6596
|
int miss = 0; |
|
6597
|
PNum v = pik_value(p, pId->z, pId->n, &miss); |
|
6598
|
if( miss==0 ) return v; |
|
6599
|
v = pik_lookup_color(0, pId); |
|
6600
|
if( v>-90.0 ) return v; |
|
6601
|
pik_error(p,pId,"no such variable"); |
|
6602
|
return 0.0; |
|
6603
|
} |
|
6604
|
|
|
6605
|
/* Convert a T_NTH token (ex: "2nd", "5th"} into a numeric value and |
|
6606
|
** return that value. Throw an error if the value is too big. |
|
6607
|
*/ |
|
6608
|
static short int pik_nth_value(Pik *p, PToken *pNth){ |
|
6609
|
int i = atoi(pNth->z); |
|
6610
|
if( i>1000 ){ |
|
6611
|
pik_error(p, pNth, "value too big - max '1000th'"); |
|
6612
|
i = 1; |
|
6613
|
} |
|
6614
|
if( i==0 && pik_token_eq(pNth,"first")==0 ) i = 1; |
|
6615
|
return (short int)i; |
|
6616
|
} |
|
6617
|
|
|
6618
|
/* Search for the NTH object. |
|
6619
|
** |
|
6620
|
** If pBasis is not NULL then it should be a [] object. Use the |
|
6621
|
** sublist of that [] object for the search. If pBasis is not a [] |
|
6622
|
** object, then throw an error. |
|
6623
|
** |
|
6624
|
** The pNth token describes the N-th search. The pNth->eCode value |
|
6625
|
** is one more than the number of items to skip. It is negative |
|
6626
|
** to search backwards. If pNth->eType==T_ID, then it is the name |
|
6627
|
** of a class to search for. If pNth->eType==T_LB, then |
|
6628
|
** search for a [] object. If pNth->eType==T_LAST, then search for |
|
6629
|
** any type. |
|
6630
|
** |
|
6631
|
** Raise an error if the item is not found. |
|
6632
|
*/ |
|
6633
|
static PObj *pik_find_nth(Pik *p, PObj *pBasis, PToken *pNth){ |
|
6634
|
PList *pList; |
|
6635
|
int i, n; |
|
6636
|
const PClass *pClass; |
|
6637
|
if( pBasis==0 ){ |
|
6638
|
pList = p->list; |
|
6639
|
}else{ |
|
6640
|
pList = pBasis->pSublist; |
|
6641
|
} |
|
6642
|
if( pList==0 ){ |
|
6643
|
pik_error(p, pNth, "no such object"); |
|
6644
|
return 0; |
|
6645
|
} |
|
6646
|
if( pNth->eType==T_LAST ){ |
|
6647
|
pClass = 0; |
|
6648
|
}else if( pNth->eType==T_LB ){ |
|
6649
|
pClass = &sublistClass; |
|
6650
|
}else{ |
|
6651
|
pClass = pik_find_class(pNth); |
|
6652
|
if( pClass==0 ){ |
|
6653
|
pik_error(0, pNth, "no such object type"); |
|
6654
|
return 0; |
|
6655
|
} |
|
6656
|
} |
|
6657
|
n = pNth->eCode; |
|
6658
|
if( n<0 ){ |
|
6659
|
for(i=pList->n-1; i>=0; i--){ |
|
6660
|
PObj *pObj = pList->a[i]; |
|
6661
|
if( pClass && pObj->type!=pClass ) continue; |
|
6662
|
n++; |
|
6663
|
if( n==0 ){ return pObj; } |
|
6664
|
} |
|
6665
|
}else{ |
|
6666
|
for(i=0; i<pList->n; i++){ |
|
6667
|
PObj *pObj = pList->a[i]; |
|
6668
|
if( pClass && pObj->type!=pClass ) continue; |
|
6669
|
n--; |
|
6670
|
if( n==0 ){ return pObj; } |
|
6671
|
} |
|
6672
|
} |
|
6673
|
pik_error(p, pNth, "no such object"); |
|
6674
|
return 0; |
|
6675
|
} |
|
6676
|
|
|
6677
|
/* Search for an object by name. |
|
6678
|
** |
|
6679
|
** Search in pBasis->pSublist if pBasis is not NULL. If pBasis is NULL |
|
6680
|
** then search in p->list. |
|
6681
|
*/ |
|
6682
|
static PObj *pik_find_byname(Pik *p, PObj *pBasis, PToken *pName){ |
|
6683
|
PList *pList; |
|
6684
|
int i, j; |
|
6685
|
if( pBasis==0 ){ |
|
6686
|
pList = p->list; |
|
6687
|
}else{ |
|
6688
|
pList = pBasis->pSublist; |
|
6689
|
} |
|
6690
|
if( pList==0 ){ |
|
6691
|
pik_error(p, pName, "no such object"); |
|
6692
|
return 0; |
|
6693
|
} |
|
6694
|
/* First look explicitly tagged objects */ |
|
6695
|
for(i=pList->n-1; i>=0; i--){ |
|
6696
|
PObj *pObj = pList->a[i]; |
|
6697
|
if( pObj->zName && pik_token_eq(pName,pObj->zName)==0 ){ |
|
6698
|
p->lastRef = pObj; |
|
6699
|
return pObj; |
|
6700
|
} |
|
6701
|
} |
|
6702
|
/* If not found, do a second pass looking for any object containing |
|
6703
|
** text which exactly matches pName */ |
|
6704
|
for(i=pList->n-1; i>=0; i--){ |
|
6705
|
PObj *pObj = pList->a[i]; |
|
6706
|
for(j=0; j<pObj->nTxt; j++){ |
|
6707
|
if( pObj->aTxt[j].n==pName->n+2 |
|
6708
|
&& memcmp(pObj->aTxt[j].z+1,pName->z,pName->n)==0 ){ |
|
6709
|
p->lastRef = pObj; |
|
6710
|
return pObj; |
|
6711
|
} |
|
6712
|
} |
|
6713
|
} |
|
6714
|
pik_error(p, pName, "no such object"); |
|
6715
|
return 0; |
|
6716
|
} |
|
6717
|
|
|
6718
|
/* Change most of the settings for the current object to be the |
|
6719
|
** same as the pOther object, or the most recent object of the same |
|
6720
|
** type if pOther is NULL. |
|
6721
|
*/ |
|
6722
|
static void pik_same(Pik *p, PObj *pOther, PToken *pErrTok){ |
|
6723
|
PObj *pObj = p->cur; |
|
6724
|
if( p->nErr ) return; |
|
6725
|
if( pOther==0 ){ |
|
6726
|
int i; |
|
6727
|
for(i=(p->list ? p->list->n : 0)-1; i>=0; i--){ |
|
6728
|
pOther = p->list->a[i]; |
|
6729
|
if( pOther->type==pObj->type ) break; |
|
6730
|
} |
|
6731
|
if( i<0 ){ |
|
6732
|
pik_error(p, pErrTok, "no prior objects of the same type"); |
|
6733
|
return; |
|
6734
|
} |
|
6735
|
} |
|
6736
|
if( pOther->nPath && pObj->type->isLine ){ |
|
6737
|
PNum dx, dy; |
|
6738
|
int i; |
|
6739
|
dx = p->aTPath[0].x - pOther->aPath[0].x; |
|
6740
|
dy = p->aTPath[0].y - pOther->aPath[0].y; |
|
6741
|
for(i=1; i<pOther->nPath; i++){ |
|
6742
|
p->aTPath[i].x = pOther->aPath[i].x + dx; |
|
6743
|
p->aTPath[i].y = pOther->aPath[i].y + dy; |
|
6744
|
} |
|
6745
|
p->nTPath = pOther->nPath; |
|
6746
|
p->mTPath = 3; |
|
6747
|
p->samePath = 1; |
|
6748
|
} |
|
6749
|
if( !pObj->type->isLine ){ |
|
6750
|
pObj->w = pOther->w; |
|
6751
|
pObj->h = pOther->h; |
|
6752
|
} |
|
6753
|
pObj->rad = pOther->rad; |
|
6754
|
pObj->sw = pOther->sw; |
|
6755
|
pObj->dashed = pOther->dashed; |
|
6756
|
pObj->dotted = pOther->dotted; |
|
6757
|
pObj->fill = pOther->fill; |
|
6758
|
pObj->color = pOther->color; |
|
6759
|
pObj->cw = pOther->cw; |
|
6760
|
pObj->larrow = pOther->larrow; |
|
6761
|
pObj->rarrow = pOther->rarrow; |
|
6762
|
pObj->bClose = pOther->bClose; |
|
6763
|
pObj->bChop = pOther->bChop; |
|
6764
|
pObj->iLayer = pOther->iLayer; |
|
6765
|
} |
|
6766
|
|
|
6767
|
|
|
6768
|
/* Return a "Place" associated with object pObj. If pEdge is NULL |
|
6769
|
** return the center of the object. Otherwise, return the corner |
|
6770
|
** described by pEdge. |
|
6771
|
*/ |
|
6772
|
static PPoint pik_place_of_elem(Pik *p, PObj *pObj, PToken *pEdge){ |
|
6773
|
PPoint pt = cZeroPoint; |
|
6774
|
const PClass *pClass; |
|
6775
|
if( pObj==0 ) return pt; |
|
6776
|
if( pEdge==0 ){ |
|
6777
|
return pObj->ptAt; |
|
6778
|
} |
|
6779
|
pClass = pObj->type; |
|
6780
|
if( pEdge->eType==T_EDGEPT || (pEdge->eEdge>0 && pEdge->eEdge<CP_END) ){ |
|
6781
|
pt = pClass->xOffset(p, pObj, pEdge->eEdge); |
|
6782
|
pt.x += pObj->ptAt.x; |
|
6783
|
pt.y += pObj->ptAt.y; |
|
6784
|
return pt; |
|
6785
|
} |
|
6786
|
if( pEdge->eType==T_START ){ |
|
6787
|
return pObj->ptEnter; |
|
6788
|
}else{ |
|
6789
|
return pObj->ptExit; |
|
6790
|
} |
|
6791
|
} |
|
6792
|
|
|
6793
|
/* Do a linear interpolation of two positions. |
|
6794
|
*/ |
|
6795
|
static PPoint pik_position_between(PNum x, PPoint p1, PPoint p2){ |
|
6796
|
PPoint out; |
|
6797
|
out.x = p2.x*x + p1.x*(1.0 - x); |
|
6798
|
out.y = p2.y*x + p1.y*(1.0 - x); |
|
6799
|
return out; |
|
6800
|
} |
|
6801
|
|
|
6802
|
/* Compute the position that is dist away from pt at an heading angle of r |
|
6803
|
** |
|
6804
|
** The angle is a compass heading in degrees. North is 0 (or 360). |
|
6805
|
** East is 90. South is 180. West is 270. And so forth. |
|
6806
|
*/ |
|
6807
|
static PPoint pik_position_at_angle(PNum dist, PNum r, PPoint pt){ |
|
6808
|
r *= 0.017453292519943295769; /* degrees to radians */ |
|
6809
|
pt.x += dist*sin(r); |
|
6810
|
pt.y += dist*cos(r); |
|
6811
|
return pt; |
|
6812
|
} |
|
6813
|
|
|
6814
|
/* Compute the position that is dist away at a compass point |
|
6815
|
*/ |
|
6816
|
static PPoint pik_position_at_hdg(PNum dist, PToken *pD, PPoint pt){ |
|
6817
|
return pik_position_at_angle(dist, pik_hdg_angle[pD->eEdge], pt); |
|
6818
|
} |
|
6819
|
|
|
6820
|
/* Return the coordinates for the n-th vertex of a line. |
|
6821
|
*/ |
|
6822
|
static PPoint pik_nth_vertex(Pik *p, PToken *pNth, PToken *pErr, PObj *pObj){ |
|
6823
|
static const PPoint zero = {0, 0}; |
|
6824
|
int n; |
|
6825
|
if( p->nErr || pObj==0 ) return p->aTPath[0]; |
|
6826
|
if( !pObj->type->isLine ){ |
|
6827
|
pik_error(p, pErr, "object is not a line"); |
|
6828
|
return zero; |
|
6829
|
} |
|
6830
|
n = atoi(pNth->z); |
|
6831
|
if( n<1 || n>pObj->nPath ){ |
|
6832
|
pik_error(p, pNth, "no such vertex"); |
|
6833
|
return zero; |
|
6834
|
} |
|
6835
|
return pObj->aPath[n-1]; |
|
6836
|
} |
|
6837
|
|
|
6838
|
/* Return the value of a property of an object. |
|
6839
|
*/ |
|
6840
|
static PNum pik_property_of(PObj *pObj, PToken *pProp){ |
|
6841
|
PNum v = 0.0; |
|
6842
|
if( pObj ){ |
|
6843
|
switch( pProp->eType ){ |
|
6844
|
case T_HEIGHT: v = pObj->h; break; |
|
6845
|
case T_WIDTH: v = pObj->w; break; |
|
6846
|
case T_RADIUS: v = pObj->rad; break; |
|
6847
|
case T_DIAMETER: v = pObj->rad*2.0; break; |
|
6848
|
case T_THICKNESS: v = pObj->sw; break; |
|
6849
|
case T_DASHED: v = pObj->dashed; break; |
|
6850
|
case T_DOTTED: v = pObj->dotted; break; |
|
6851
|
case T_FILL: v = pObj->fill; break; |
|
6852
|
case T_COLOR: v = pObj->color; break; |
|
6853
|
case T_X: v = pObj->ptAt.x; break; |
|
6854
|
case T_Y: v = pObj->ptAt.y; break; |
|
6855
|
case T_TOP: v = pObj->bbox.ne.y; break; |
|
6856
|
case T_BOTTOM: v = pObj->bbox.sw.y; break; |
|
6857
|
case T_LEFT: v = pObj->bbox.sw.x; break; |
|
6858
|
case T_RIGHT: v = pObj->bbox.ne.x; break; |
|
6859
|
} |
|
6860
|
} |
|
6861
|
return v; |
|
6862
|
} |
|
6863
|
|
|
6864
|
/* Compute one of the built-in functions |
|
6865
|
*/ |
|
6866
|
static PNum pik_func(Pik *p, PToken *pFunc, PNum x, PNum y){ |
|
6867
|
PNum v = 0.0; |
|
6868
|
switch( pFunc->eCode ){ |
|
6869
|
case FN_ABS: v = x<0.0 ? -x : x; break; |
|
6870
|
case FN_COS: v = cos(x); break; |
|
6871
|
case FN_INT: v = rint(x); break; |
|
6872
|
case FN_SIN: v = sin(x); break; |
|
6873
|
case FN_SQRT: |
|
6874
|
if( x<0.0 ){ |
|
6875
|
pik_error(p, pFunc, "sqrt of negative value"); |
|
6876
|
v = 0.0; |
|
6877
|
}else{ |
|
6878
|
v = sqrt(x); |
|
6879
|
} |
|
6880
|
break; |
|
6881
|
case FN_MAX: v = x>y ? x : y; break; |
|
6882
|
case FN_MIN: v = x<y ? x : y; break; |
|
6883
|
default: v = 0.0; |
|
6884
|
} |
|
6885
|
return v; |
|
6886
|
} |
|
6887
|
|
|
6888
|
/* Attach a name to an object |
|
6889
|
*/ |
|
6890
|
static void pik_elem_setname(Pik *p, PObj *pObj, PToken *pName){ |
|
6891
|
if( pObj==0 ) return; |
|
6892
|
if( pName==0 ) return; |
|
6893
|
free(pObj->zName); |
|
6894
|
pObj->zName = malloc(pName->n+1); |
|
6895
|
if( pObj->zName==0 ){ |
|
6896
|
pik_error(p,0,0); |
|
6897
|
}else{ |
|
6898
|
memcpy(pObj->zName,pName->z,pName->n); |
|
6899
|
pObj->zName[pName->n] = 0; |
|
6900
|
} |
|
6901
|
return; |
|
6902
|
} |
|
6903
|
|
|
6904
|
/* |
|
6905
|
** Search for object located at *pCenter that has an xChop method and |
|
6906
|
** that does not enclose point pOther. |
|
6907
|
** |
|
6908
|
** Return a pointer to the object, or NULL if not found. |
|
6909
|
*/ |
|
6910
|
static PObj *pik_find_chopper(PList *pList, PPoint *pCenter, PPoint *pOther){ |
|
6911
|
int i; |
|
6912
|
if( pList==0 ) return 0; |
|
6913
|
for(i=pList->n-1; i>=0; i--){ |
|
6914
|
PObj *pObj = pList->a[i]; |
|
6915
|
if( pObj->type->xChop!=0 |
|
6916
|
&& pObj->ptAt.x==pCenter->x |
|
6917
|
&& pObj->ptAt.y==pCenter->y |
|
6918
|
&& !pik_bbox_contains_point(&pObj->bbox, pOther) |
|
6919
|
){ |
|
6920
|
return pObj; |
|
6921
|
}else if( pObj->pSublist ){ |
|
6922
|
pObj = pik_find_chopper(pObj->pSublist,pCenter,pOther); |
|
6923
|
if( pObj ) return pObj; |
|
6924
|
} |
|
6925
|
} |
|
6926
|
return 0; |
|
6927
|
} |
|
6928
|
|
|
6929
|
/* |
|
6930
|
** There is a line traveling from pFrom to pTo. |
|
6931
|
** |
|
6932
|
** If pObj is not null and is a choppable object, then chop at |
|
6933
|
** the boundary of pObj - where the line crosses the boundary |
|
6934
|
** of pObj. |
|
6935
|
** |
|
6936
|
** If pObj is NULL or has no xChop method, then search for some |
|
6937
|
** other object centered at pTo that is choppable and use it |
|
6938
|
** instead. |
|
6939
|
*/ |
|
6940
|
static void pik_autochop(Pik *p, PPoint *pFrom, PPoint *pTo, PObj *pObj){ |
|
6941
|
if( pObj==0 || pObj->type->xChop==0 ){ |
|
6942
|
pObj = pik_find_chopper(p->list, pTo, pFrom); |
|
6943
|
} |
|
6944
|
if( pObj ){ |
|
6945
|
*pTo = pObj->type->xChop(p, pObj, pFrom); |
|
6946
|
} |
|
6947
|
} |
|
6948
|
|
|
6949
|
/* This routine runs after all attributes have been received |
|
6950
|
** on an object. |
|
6951
|
*/ |
|
6952
|
static void pik_after_adding_attributes(Pik *p, PObj *pObj){ |
|
6953
|
int i; |
|
6954
|
PPoint ofst; |
|
6955
|
PNum dx, dy; |
|
6956
|
|
|
6957
|
if( p->nErr ) return; |
|
6958
|
|
|
6959
|
/* Position block objects */ |
|
6960
|
if( pObj->type->isLine==0 ){ |
|
6961
|
/* A height or width less than or equal to zero means "autofit". |
|
6962
|
** Change the height or width to be big enough to contain the text, |
|
6963
|
*/ |
|
6964
|
if( pObj->h<=0.0 ){ |
|
6965
|
if( pObj->nTxt==0 ){ |
|
6966
|
pObj->h = 0.0; |
|
6967
|
}else if( pObj->w<=0.0 ){ |
|
6968
|
pik_size_to_fit(p, pObj, &pObj->errTok, 3); |
|
6969
|
}else{ |
|
6970
|
pik_size_to_fit(p, pObj, &pObj->errTok, 2); |
|
6971
|
} |
|
6972
|
} |
|
6973
|
if( pObj->w<=0.0 ){ |
|
6974
|
if( pObj->nTxt==0 ){ |
|
6975
|
pObj->w = 0.0; |
|
6976
|
}else{ |
|
6977
|
pik_size_to_fit(p, pObj, &pObj->errTok, 1); |
|
6978
|
} |
|
6979
|
} |
|
6980
|
ofst = pik_elem_offset(p, pObj, pObj->eWith); |
|
6981
|
dx = (pObj->with.x - ofst.x) - pObj->ptAt.x; |
|
6982
|
dy = (pObj->with.y - ofst.y) - pObj->ptAt.y; |
|
6983
|
if( dx!=0 || dy!=0 ){ |
|
6984
|
pik_elem_move(pObj, dx, dy); |
|
6985
|
} |
|
6986
|
} |
|
6987
|
|
|
6988
|
/* For a line object with no movement specified, a single movement |
|
6989
|
** of the default length in the current direction |
|
6990
|
*/ |
|
6991
|
if( pObj->type->isLine && p->nTPath<2 ){ |
|
6992
|
pik_next_rpath(p, 0); |
|
6993
|
assert( p->nTPath==2 ); |
|
6994
|
switch( pObj->inDir ){ |
|
6995
|
default: p->aTPath[1].x += pObj->w; break; |
|
6996
|
case DIR_DOWN: p->aTPath[1].y -= pObj->h; break; |
|
6997
|
case DIR_LEFT: p->aTPath[1].x -= pObj->w; break; |
|
6998
|
case DIR_UP: p->aTPath[1].y += pObj->h; break; |
|
6999
|
} |
|
7000
|
if( pObj->type->xInit==arcInit ){ |
|
7001
|
pObj->outDir = (pObj->inDir + (pObj->cw ? 1 : 3))%4; |
|
7002
|
p->eDir = (unsigned char)pObj->outDir; |
|
7003
|
switch( pObj->outDir ){ |
|
7004
|
default: p->aTPath[1].x += pObj->w; break; |
|
7005
|
case DIR_DOWN: p->aTPath[1].y -= pObj->h; break; |
|
7006
|
case DIR_LEFT: p->aTPath[1].x -= pObj->w; break; |
|
7007
|
case DIR_UP: p->aTPath[1].y += pObj->h; break; |
|
7008
|
} |
|
7009
|
} |
|
7010
|
} |
|
7011
|
|
|
7012
|
/* Initialize the bounding box prior to running xCheck */ |
|
7013
|
pik_bbox_init(&pObj->bbox); |
|
7014
|
|
|
7015
|
/* Run object-specific code */ |
|
7016
|
if( pObj->type->xCheck!=0 ){ |
|
7017
|
pObj->type->xCheck(p,pObj); |
|
7018
|
if( p->nErr ) return; |
|
7019
|
} |
|
7020
|
|
|
7021
|
/* Compute final bounding box, entry and exit points, center |
|
7022
|
** point (ptAt) and path for the object |
|
7023
|
*/ |
|
7024
|
if( pObj->type->isLine ){ |
|
7025
|
pObj->aPath = malloc( sizeof(PPoint)*p->nTPath ); |
|
7026
|
if( pObj->aPath==0 ){ |
|
7027
|
pik_error(p, 0, 0); |
|
7028
|
return; |
|
7029
|
}else{ |
|
7030
|
pObj->nPath = p->nTPath; |
|
7031
|
for(i=0; i<p->nTPath; i++){ |
|
7032
|
pObj->aPath[i] = p->aTPath[i]; |
|
7033
|
} |
|
7034
|
} |
|
7035
|
|
|
7036
|
/* "chop" processing: |
|
7037
|
** If the line goes to the center of an object with an |
|
7038
|
** xChop method, then use the xChop method to trim the line. |
|
7039
|
*/ |
|
7040
|
if( pObj->bChop && pObj->nPath>=2 ){ |
|
7041
|
int n = pObj->nPath; |
|
7042
|
pik_autochop(p, &pObj->aPath[n-2], &pObj->aPath[n-1], pObj->pTo); |
|
7043
|
pik_autochop(p, &pObj->aPath[1], &pObj->aPath[0], pObj->pFrom); |
|
7044
|
} |
|
7045
|
|
|
7046
|
pObj->ptEnter = pObj->aPath[0]; |
|
7047
|
pObj->ptExit = pObj->aPath[pObj->nPath-1]; |
|
7048
|
|
|
7049
|
/* Compute the center of the line based on the bounding box over |
|
7050
|
** the vertexes. This is a difference from PIC. In Pikchr, the |
|
7051
|
** center of a line is the center of its bounding box. In PIC, the |
|
7052
|
** center of a line is halfway between its .start and .end. For |
|
7053
|
** straight lines, this is the same point, but for multi-segment |
|
7054
|
** lines the result is usually diferent */ |
|
7055
|
for(i=0; i<pObj->nPath; i++){ |
|
7056
|
pik_bbox_add_xy(&pObj->bbox, pObj->aPath[i].x, pObj->aPath[i].y); |
|
7057
|
} |
|
7058
|
pObj->ptAt.x = (pObj->bbox.ne.x + pObj->bbox.sw.x)/2.0; |
|
7059
|
pObj->ptAt.y = (pObj->bbox.ne.y + pObj->bbox.sw.y)/2.0; |
|
7060
|
|
|
7061
|
/* Reset the width and height of the object to be the width and height |
|
7062
|
** of the bounding box over vertexes */ |
|
7063
|
pObj->w = pObj->bbox.ne.x - pObj->bbox.sw.x; |
|
7064
|
pObj->h = pObj->bbox.ne.y - pObj->bbox.sw.y; |
|
7065
|
|
|
7066
|
/* If this is a polygon (if it has the "close" attribute), then |
|
7067
|
** adjust the exit point */ |
|
7068
|
if( pObj->bClose ){ |
|
7069
|
/* For "closed" lines, the .end is one of the .e, .s, .w, or .n |
|
7070
|
** points of the bounding box, as with block objects. */ |
|
7071
|
pik_elem_set_exit(pObj, pObj->inDir); |
|
7072
|
} |
|
7073
|
}else{ |
|
7074
|
PNum w2 = pObj->w/2.0; |
|
7075
|
PNum h2 = pObj->h/2.0; |
|
7076
|
pObj->ptEnter = pObj->ptAt; |
|
7077
|
pObj->ptExit = pObj->ptAt; |
|
7078
|
switch( pObj->inDir ){ |
|
7079
|
default: pObj->ptEnter.x -= w2; break; |
|
7080
|
case DIR_LEFT: pObj->ptEnter.x += w2; break; |
|
7081
|
case DIR_UP: pObj->ptEnter.y -= h2; break; |
|
7082
|
case DIR_DOWN: pObj->ptEnter.y += h2; break; |
|
7083
|
} |
|
7084
|
switch( pObj->outDir ){ |
|
7085
|
default: pObj->ptExit.x += w2; break; |
|
7086
|
case DIR_LEFT: pObj->ptExit.x -= w2; break; |
|
7087
|
case DIR_UP: pObj->ptExit.y += h2; break; |
|
7088
|
case DIR_DOWN: pObj->ptExit.y -= h2; break; |
|
7089
|
} |
|
7090
|
pik_bbox_add_xy(&pObj->bbox, pObj->ptAt.x - w2, pObj->ptAt.y - h2); |
|
7091
|
pik_bbox_add_xy(&pObj->bbox, pObj->ptAt.x + w2, pObj->ptAt.y + h2); |
|
7092
|
} |
|
7093
|
p->eDir = (unsigned char)pObj->outDir; |
|
7094
|
} |
|
7095
|
|
|
7096
|
/* Show basic information about each object as a comment in the |
|
7097
|
** generated HTML. Used for testing and debugging. Activated |
|
7098
|
** by the (undocumented) "debug = 1;" |
|
7099
|
** command. |
|
7100
|
*/ |
|
7101
|
static void pik_elem_render(Pik *p, PObj *pObj){ |
|
7102
|
char *zDir; |
|
7103
|
if( pObj==0 ) return; |
|
7104
|
pik_append(p,"<!-- ", -1); |
|
7105
|
if( pObj->zName ){ |
|
7106
|
pik_append_text(p, pObj->zName, -1, 0); |
|
7107
|
pik_append(p, ": ", 2); |
|
7108
|
} |
|
7109
|
pik_append_text(p, pObj->type->zName, -1, 0); |
|
7110
|
if( pObj->nTxt ){ |
|
7111
|
pik_append(p, " \"", 2); |
|
7112
|
pik_append_text(p, pObj->aTxt[0].z+1, pObj->aTxt[0].n-2, 1); |
|
7113
|
pik_append(p, "\"", 1); |
|
7114
|
} |
|
7115
|
pik_append_num(p, " w=", pObj->w); |
|
7116
|
pik_append_num(p, " h=", pObj->h); |
|
7117
|
pik_append_point(p, " center=", &pObj->ptAt); |
|
7118
|
pik_append_point(p, " enter=", &pObj->ptEnter); |
|
7119
|
switch( pObj->outDir ){ |
|
7120
|
default: zDir = " right"; break; |
|
7121
|
case DIR_LEFT: zDir = " left"; break; |
|
7122
|
case DIR_UP: zDir = " up"; break; |
|
7123
|
case DIR_DOWN: zDir = " down"; break; |
|
7124
|
} |
|
7125
|
pik_append_point(p, " exit=", &pObj->ptExit); |
|
7126
|
pik_append(p, zDir, -1); |
|
7127
|
pik_append(p, " -->\n", -1); |
|
7128
|
} |
|
7129
|
|
|
7130
|
/* Render a list of objects |
|
7131
|
*/ |
|
7132
|
void pik_elist_render(Pik *p, PList *pList){ |
|
7133
|
int i; |
|
7134
|
int iNextLayer = 0; |
|
7135
|
int iThisLayer; |
|
7136
|
int bMoreToDo; |
|
7137
|
int miss = 0; |
|
7138
|
int mDebug = pik_value_int(p, "debug", 5, 0); |
|
7139
|
PNum colorLabel; |
|
7140
|
do{ |
|
7141
|
bMoreToDo = 0; |
|
7142
|
iThisLayer = iNextLayer; |
|
7143
|
iNextLayer = 0x7fffffff; |
|
7144
|
for(i=0; i<pList->n; i++){ |
|
7145
|
PObj *pObj = pList->a[i]; |
|
7146
|
void (*xRender)(Pik*,PObj*); |
|
7147
|
if( pObj->iLayer>iThisLayer ){ |
|
7148
|
if( pObj->iLayer<iNextLayer ) iNextLayer = pObj->iLayer; |
|
7149
|
bMoreToDo = 1; |
|
7150
|
continue; /* Defer until another round */ |
|
7151
|
}else if( pObj->iLayer<iThisLayer ){ |
|
7152
|
continue; |
|
7153
|
} |
|
7154
|
if( mDebug & 1 ) pik_elem_render(p, pObj); |
|
7155
|
xRender = pObj->type->xRender; |
|
7156
|
if( xRender ){ |
|
7157
|
xRender(p, pObj); |
|
7158
|
} |
|
7159
|
if( pObj->pSublist ){ |
|
7160
|
pik_elist_render(p, pObj->pSublist); |
|
7161
|
} |
|
7162
|
} |
|
7163
|
}while( bMoreToDo ); |
|
7164
|
|
|
7165
|
/* If the color_debug_label value is defined, then go through |
|
7166
|
** and paint a dot at every label location */ |
|
7167
|
colorLabel = pik_value(p, "debug_label_color", 17, &miss); |
|
7168
|
if( miss==0 && colorLabel>=0.0 ){ |
|
7169
|
PObj dot; |
|
7170
|
memset(&dot, 0, sizeof(dot)); |
|
7171
|
dot.type = &noopClass; |
|
7172
|
dot.rad = 0.015; |
|
7173
|
dot.sw = 0.015; |
|
7174
|
dot.fill = colorLabel; |
|
7175
|
dot.color = colorLabel; |
|
7176
|
dot.nTxt = 1; |
|
7177
|
dot.aTxt[0].eCode = TP_ABOVE; |
|
7178
|
for(i=0; i<pList->n; i++){ |
|
7179
|
PObj *pObj = pList->a[i]; |
|
7180
|
if( pObj->zName==0 ) continue; |
|
7181
|
dot.ptAt = pObj->ptAt; |
|
7182
|
dot.aTxt[0].z = pObj->zName; |
|
7183
|
dot.aTxt[0].n = (int)strlen(pObj->zName); |
|
7184
|
dotRender(p, &dot); |
|
7185
|
} |
|
7186
|
} |
|
7187
|
} |
|
7188
|
|
|
7189
|
/* Add all objects of the list pList to the bounding box |
|
7190
|
*/ |
|
7191
|
static void pik_bbox_add_elist(Pik *p, PList *pList, PNum wArrow){ |
|
7192
|
int i; |
|
7193
|
for(i=0; i<pList->n; i++){ |
|
7194
|
PObj *pObj = pList->a[i]; |
|
7195
|
if( pObj->sw>=0.0 ) pik_bbox_addbox(&p->bbox, &pObj->bbox); |
|
7196
|
pik_append_txt(p, pObj, &p->bbox); |
|
7197
|
if( pObj->pSublist ) pik_bbox_add_elist(p, pObj->pSublist, wArrow); |
|
7198
|
|
|
7199
|
|
|
7200
|
/* Expand the bounding box to account for arrowheads on lines */ |
|
7201
|
if( pObj->type->isLine && pObj->nPath>0 ){ |
|
7202
|
if( pObj->larrow ){ |
|
7203
|
pik_bbox_addellipse(&p->bbox, pObj->aPath[0].x, pObj->aPath[0].y, |
|
7204
|
wArrow, wArrow); |
|
7205
|
} |
|
7206
|
if( pObj->rarrow ){ |
|
7207
|
int j = pObj->nPath-1; |
|
7208
|
pik_bbox_addellipse(&p->bbox, pObj->aPath[j].x, pObj->aPath[j].y, |
|
7209
|
wArrow, wArrow); |
|
7210
|
} |
|
7211
|
} |
|
7212
|
} |
|
7213
|
} |
|
7214
|
|
|
7215
|
/* Recompute key layout parameters from variables. */ |
|
7216
|
static void pik_compute_layout_settings(Pik *p){ |
|
7217
|
PNum thickness; /* Line thickness */ |
|
7218
|
PNum wArrow; /* Width of arrowheads */ |
|
7219
|
|
|
7220
|
/* Set up rendering parameters */ |
|
7221
|
if( p->bLayoutVars ) return; |
|
7222
|
thickness = pik_value(p,"thickness",9,0); |
|
7223
|
if( thickness<=0.01 ) thickness = 0.01; |
|
7224
|
wArrow = 0.5*pik_value(p,"arrowwid",8,0); |
|
7225
|
p->wArrow = wArrow/thickness; |
|
7226
|
p->hArrow = pik_value(p,"arrowht",7,0)/thickness; |
|
7227
|
p->fontScale = pik_value(p,"fontscale",9,0); |
|
7228
|
if( p->fontScale<=0.0 ) p->fontScale = 1.0; |
|
7229
|
p->rScale = 144.0; |
|
7230
|
p->charWidth = pik_value(p,"charwid",7,0)*p->fontScale; |
|
7231
|
p->charHeight = pik_value(p,"charht",6,0)*p->fontScale; |
|
7232
|
p->bLayoutVars = 1; |
|
7233
|
} |
|
7234
|
|
|
7235
|
/* Render a list of objects. Write the SVG into p->zOut. |
|
7236
|
** Delete the input object_list before returnning. |
|
7237
|
*/ |
|
7238
|
static void pik_render(Pik *p, PList *pList){ |
|
7239
|
if( pList==0 ) return; |
|
7240
|
if( p->nErr==0 ){ |
|
7241
|
PNum thickness; /* Stroke width */ |
|
7242
|
PNum margin; /* Extra bounding box margin */ |
|
7243
|
PNum w, h; /* Drawing width and height */ |
|
7244
|
PNum wArrow; |
|
7245
|
PNum pikScale; /* Value of the "scale" variable */ |
|
7246
|
int miss = 0; |
|
7247
|
|
|
7248
|
/* Set up rendering parameters */ |
|
7249
|
pik_compute_layout_settings(p); |
|
7250
|
thickness = pik_value(p,"thickness",9,0); |
|
7251
|
if( thickness<=0.01 ) thickness = 0.01; |
|
7252
|
margin = pik_value(p,"margin",6,0); |
|
7253
|
margin += thickness; |
|
7254
|
wArrow = p->wArrow*thickness; |
|
7255
|
miss = 0; |
|
7256
|
p->fgcolor = pik_value_int(p,"fgcolor",7,&miss); |
|
7257
|
if( miss ){ |
|
7258
|
PToken t; |
|
7259
|
t.z = "fgcolor"; |
|
7260
|
t.n = 7; |
|
7261
|
p->fgcolor = pik_round(pik_lookup_color(0, &t)); |
|
7262
|
} |
|
7263
|
miss = 0; |
|
7264
|
p->bgcolor = pik_value_int(p,"bgcolor",7,&miss); |
|
7265
|
if( miss ){ |
|
7266
|
PToken t; |
|
7267
|
t.z = "bgcolor"; |
|
7268
|
t.n = 7; |
|
7269
|
p->bgcolor = pik_round(pik_lookup_color(0, &t)); |
|
7270
|
} |
|
7271
|
|
|
7272
|
/* Compute a bounding box over all objects so that we can know |
|
7273
|
** how big to declare the SVG canvas */ |
|
7274
|
pik_bbox_init(&p->bbox); |
|
7275
|
pik_bbox_add_elist(p, pList, wArrow); |
|
7276
|
|
|
7277
|
/* Expand the bounding box slightly to account for line thickness |
|
7278
|
** and the optional "margin = EXPR" setting. */ |
|
7279
|
p->bbox.ne.x += margin + pik_value(p,"rightmargin",11,0); |
|
7280
|
p->bbox.ne.y += margin + pik_value(p,"topmargin",9,0); |
|
7281
|
p->bbox.sw.x -= margin + pik_value(p,"leftmargin",10,0); |
|
7282
|
p->bbox.sw.y -= margin + pik_value(p,"bottommargin",12,0); |
|
7283
|
|
|
7284
|
/* Output the SVG */ |
|
7285
|
pik_append(p, "<svg xmlns='http://www.w3.org/2000/svg'" |
|
7286
|
" style='font-size:initial;'",-1); |
|
7287
|
if( p->zClass ){ |
|
7288
|
pik_append(p, " class=\"", -1); |
|
7289
|
pik_append(p, p->zClass, -1); |
|
7290
|
pik_append(p, "\"", 1); |
|
7291
|
} |
|
7292
|
w = p->bbox.ne.x - p->bbox.sw.x; |
|
7293
|
h = p->bbox.ne.y - p->bbox.sw.y; |
|
7294
|
p->wSVG = pik_round(p->rScale*w); |
|
7295
|
p->hSVG = pik_round(p->rScale*h); |
|
7296
|
pikScale = pik_value(p,"scale",5,0); |
|
7297
|
if( pikScale>=0.001 && pikScale<=1000.0 |
|
7298
|
&& (pikScale<0.99 || pikScale>1.01) |
|
7299
|
){ |
|
7300
|
p->wSVG = pik_round(p->wSVG*pikScale); |
|
7301
|
p->hSVG = pik_round(p->hSVG*pikScale); |
|
7302
|
pik_append_num(p, " width=\"", p->wSVG); |
|
7303
|
pik_append_num(p, "\" height=\"", p->hSVG); |
|
7304
|
pik_append(p, "\"", 1); |
|
7305
|
} |
|
7306
|
pik_append_dis(p, " viewBox=\"0 0 ",w,""); |
|
7307
|
pik_append_dis(p, " ",h,"\""); |
|
7308
|
pik_append(p, " data-pikchr-date=\"" MANIFEST_ISODATE "\">\n", -1); |
|
7309
|
pik_elist_render(p, pList); |
|
7310
|
pik_append(p,"</svg>\n", -1); |
|
7311
|
}else{ |
|
7312
|
p->wSVG = -1; |
|
7313
|
p->hSVG = -1; |
|
7314
|
} |
|
7315
|
pik_elist_free(p, pList); |
|
7316
|
} |
|
7317
|
|
|
7318
|
|
|
7319
|
|
|
7320
|
/* |
|
7321
|
** An array of this structure defines a list of keywords. |
|
7322
|
*/ |
|
7323
|
typedef struct PikWord { |
|
7324
|
char *zWord; /* Text of the keyword */ |
|
7325
|
unsigned char nChar; /* Length of keyword text in bytes */ |
|
7326
|
unsigned char eType; /* Token code */ |
|
7327
|
unsigned char eCode; /* Extra code for the token */ |
|
7328
|
unsigned char eEdge; /* CP_* code for corner/edge keywords */ |
|
7329
|
} PikWord; |
|
7330
|
|
|
7331
|
/* |
|
7332
|
** Keywords |
|
7333
|
*/ |
|
7334
|
static const PikWord pik_keywords[] = { |
|
7335
|
{ "above", 5, T_ABOVE, 0, 0 }, |
|
7336
|
{ "abs", 3, T_FUNC1, FN_ABS, 0 }, |
|
7337
|
{ "aligned", 7, T_ALIGNED, 0, 0 }, |
|
7338
|
{ "and", 3, T_AND, 0, 0 }, |
|
7339
|
{ "as", 2, T_AS, 0, 0 }, |
|
7340
|
{ "assert", 6, T_ASSERT, 0, 0 }, |
|
7341
|
{ "at", 2, T_AT, 0, 0 }, |
|
7342
|
{ "behind", 6, T_BEHIND, 0, 0 }, |
|
7343
|
{ "below", 5, T_BELOW, 0, 0 }, |
|
7344
|
{ "between", 7, T_BETWEEN, 0, 0 }, |
|
7345
|
{ "big", 3, T_BIG, 0, 0 }, |
|
7346
|
{ "bold", 4, T_BOLD, 0, 0 }, |
|
7347
|
{ "bot", 3, T_EDGEPT, 0, CP_S }, |
|
7348
|
{ "bottom", 6, T_BOTTOM, 0, CP_S }, |
|
7349
|
{ "c", 1, T_EDGEPT, 0, CP_C }, |
|
7350
|
{ "ccw", 3, T_CCW, 0, 0 }, |
|
7351
|
{ "center", 6, T_CENTER, 0, CP_C }, |
|
7352
|
{ "chop", 4, T_CHOP, 0, 0 }, |
|
7353
|
{ "close", 5, T_CLOSE, 0, 0 }, |
|
7354
|
{ "color", 5, T_COLOR, 0, 0 }, |
|
7355
|
{ "cos", 3, T_FUNC1, FN_COS, 0 }, |
|
7356
|
{ "cw", 2, T_CW, 0, 0 }, |
|
7357
|
{ "dashed", 6, T_DASHED, 0, 0 }, |
|
7358
|
{ "define", 6, T_DEFINE, 0, 0 }, |
|
7359
|
{ "diameter", 8, T_DIAMETER, 0, 0 }, |
|
7360
|
{ "dist", 4, T_DIST, 0, 0 }, |
|
7361
|
{ "dotted", 6, T_DOTTED, 0, 0 }, |
|
7362
|
{ "down", 4, T_DOWN, DIR_DOWN, 0 }, |
|
7363
|
{ "e", 1, T_EDGEPT, 0, CP_E }, |
|
7364
|
{ "east", 4, T_EDGEPT, 0, CP_E }, |
|
7365
|
{ "end", 3, T_END, 0, CP_END }, |
|
7366
|
{ "even", 4, T_EVEN, 0, 0 }, |
|
7367
|
{ "fill", 4, T_FILL, 0, 0 }, |
|
7368
|
{ "first", 5, T_NTH, 0, 0 }, |
|
7369
|
{ "fit", 3, T_FIT, 0, 0 }, |
|
7370
|
{ "from", 4, T_FROM, 0, 0 }, |
|
7371
|
{ "go", 2, T_GO, 0, 0 }, |
|
7372
|
{ "heading", 7, T_HEADING, 0, 0 }, |
|
7373
|
{ "height", 6, T_HEIGHT, 0, 0 }, |
|
7374
|
{ "ht", 2, T_HEIGHT, 0, 0 }, |
|
7375
|
{ "in", 2, T_IN, 0, 0 }, |
|
7376
|
{ "int", 3, T_FUNC1, FN_INT, 0 }, |
|
7377
|
{ "invis", 5, T_INVIS, 0, 0 }, |
|
7378
|
{ "invisible", 9, T_INVIS, 0, 0 }, |
|
7379
|
{ "italic", 6, T_ITALIC, 0, 0 }, |
|
7380
|
{ "last", 4, T_LAST, 0, 0 }, |
|
7381
|
{ "left", 4, T_LEFT, DIR_LEFT, CP_W }, |
|
7382
|
{ "ljust", 5, T_LJUST, 0, 0 }, |
|
7383
|
{ "max", 3, T_FUNC2, FN_MAX, 0 }, |
|
7384
|
{ "min", 3, T_FUNC2, FN_MIN, 0 }, |
|
7385
|
{ "mono", 4, T_MONO, 0, 0 }, |
|
7386
|
{ "monospace", 9, T_MONO, 0, 0 }, |
|
7387
|
{ "n", 1, T_EDGEPT, 0, CP_N }, |
|
7388
|
{ "ne", 2, T_EDGEPT, 0, CP_NE }, |
|
7389
|
{ "north", 5, T_EDGEPT, 0, CP_N }, |
|
7390
|
{ "nw", 2, T_EDGEPT, 0, CP_NW }, |
|
7391
|
{ "of", 2, T_OF, 0, 0 }, |
|
7392
|
{ "pikchr_date",11, T_ISODATE, 0, 0, }, |
|
7393
|
{ "previous", 8, T_LAST, 0, 0, }, |
|
7394
|
{ "print", 5, T_PRINT, 0, 0 }, |
|
7395
|
{ "rad", 3, T_RADIUS, 0, 0 }, |
|
7396
|
{ "radius", 6, T_RADIUS, 0, 0 }, |
|
7397
|
{ "right", 5, T_RIGHT, DIR_RIGHT, CP_E }, |
|
7398
|
{ "rjust", 5, T_RJUST, 0, 0 }, |
|
7399
|
{ "s", 1, T_EDGEPT, 0, CP_S }, |
|
7400
|
{ "same", 4, T_SAME, 0, 0 }, |
|
7401
|
{ "se", 2, T_EDGEPT, 0, CP_SE }, |
|
7402
|
{ "sin", 3, T_FUNC1, FN_SIN, 0 }, |
|
7403
|
{ "small", 5, T_SMALL, 0, 0 }, |
|
7404
|
{ "solid", 5, T_SOLID, 0, 0 }, |
|
7405
|
{ "south", 5, T_EDGEPT, 0, CP_S }, |
|
7406
|
{ "sqrt", 4, T_FUNC1, FN_SQRT, 0 }, |
|
7407
|
{ "start", 5, T_START, 0, CP_START }, |
|
7408
|
{ "sw", 2, T_EDGEPT, 0, CP_SW }, |
|
7409
|
{ "t", 1, T_TOP, 0, CP_N }, |
|
7410
|
{ "the", 3, T_THE, 0, 0 }, |
|
7411
|
{ "then", 4, T_THEN, 0, 0 }, |
|
7412
|
{ "thick", 5, T_THICK, 0, 0 }, |
|
7413
|
{ "thickness", 9, T_THICKNESS, 0, 0 }, |
|
7414
|
{ "thin", 4, T_THIN, 0, 0 }, |
|
7415
|
{ "this", 4, T_THIS, 0, 0 }, |
|
7416
|
{ "to", 2, T_TO, 0, 0 }, |
|
7417
|
{ "top", 3, T_TOP, 0, CP_N }, |
|
7418
|
{ "until", 5, T_UNTIL, 0, 0 }, |
|
7419
|
{ "up", 2, T_UP, DIR_UP, 0 }, |
|
7420
|
{ "vertex", 6, T_VERTEX, 0, 0 }, |
|
7421
|
{ "w", 1, T_EDGEPT, 0, CP_W }, |
|
7422
|
{ "way", 3, T_WAY, 0, 0 }, |
|
7423
|
{ "west", 4, T_EDGEPT, 0, CP_W }, |
|
7424
|
{ "wid", 3, T_WIDTH, 0, 0 }, |
|
7425
|
{ "width", 5, T_WIDTH, 0, 0 }, |
|
7426
|
{ "with", 4, T_WITH, 0, 0 }, |
|
7427
|
{ "x", 1, T_X, 0, 0 }, |
|
7428
|
{ "y", 1, T_Y, 0, 0 }, |
|
7429
|
}; |
|
7430
|
|
|
7431
|
/* |
|
7432
|
** Search a PikWordlist for the given keyword. Return a pointer to the |
|
7433
|
** keyword entry found. Or return 0 if not found. |
|
7434
|
*/ |
|
7435
|
static const PikWord *pik_find_word( |
|
7436
|
const char *zIn, /* Word to search for */ |
|
7437
|
int n, /* Length of zIn */ |
|
7438
|
const PikWord *aList, /* List to search */ |
|
7439
|
int nList /* Number of entries in aList */ |
|
7440
|
){ |
|
7441
|
int first = 0; |
|
7442
|
int last = nList-1; |
|
7443
|
while( first<=last ){ |
|
7444
|
int mid = (first + last)/2; |
|
7445
|
int sz = aList[mid].nChar; |
|
7446
|
int c = strncmp(zIn, aList[mid].zWord, sz<n ? sz : n); |
|
7447
|
if( c==0 ){ |
|
7448
|
c = n - sz; |
|
7449
|
if( c==0 ) return &aList[mid]; |
|
7450
|
} |
|
7451
|
if( c<0 ){ |
|
7452
|
last = mid-1; |
|
7453
|
}else{ |
|
7454
|
first = mid+1; |
|
7455
|
} |
|
7456
|
} |
|
7457
|
return 0; |
|
7458
|
} |
|
7459
|
|
|
7460
|
/* |
|
7461
|
** Set a symbolic debugger breakpoint on this routine to receive a |
|
7462
|
** breakpoint when the "#breakpoint" token is parsed. |
|
7463
|
*/ |
|
7464
|
static void pik_breakpoint(const unsigned char *z){ |
|
7465
|
/* Prevent C compilers from optimizing out this routine. */ |
|
7466
|
if( z[2]=='X' ) exit(1); |
|
7467
|
} |
|
7468
|
|
|
7469
|
|
|
7470
|
/* |
|
7471
|
** Return the length of next token. The token starts on |
|
7472
|
** the pToken->z character. Fill in other fields of the |
|
7473
|
** pToken object as appropriate. |
|
7474
|
*/ |
|
7475
|
static int pik_token_length(PToken *pToken, int bAllowCodeBlock){ |
|
7476
|
const unsigned char *z = (const unsigned char*)pToken->z; |
|
7477
|
int i; |
|
7478
|
unsigned char c, c2; |
|
7479
|
switch( z[0] ){ |
|
7480
|
case '\\': { |
|
7481
|
pToken->eType = T_WHITESPACE; |
|
7482
|
for(i=1; z[i]=='\r' || z[i]==' ' || z[i]=='\t'; i++){} |
|
7483
|
if( z[i]=='\n' ) return i+1; |
|
7484
|
pToken->eType = T_ERROR; |
|
7485
|
return 1; |
|
7486
|
} |
|
7487
|
case ';': |
|
7488
|
case '\n': { |
|
7489
|
pToken->eType = T_EOL; |
|
7490
|
return 1; |
|
7491
|
} |
|
7492
|
case '"': { |
|
7493
|
for(i=1; (c = z[i])!=0; i++){ |
|
7494
|
if( c=='\\' ){ |
|
7495
|
if( z[i+1]==0 ) break; |
|
7496
|
i++; |
|
7497
|
continue; |
|
7498
|
} |
|
7499
|
if( c=='"' ){ |
|
7500
|
pToken->eType = T_STRING; |
|
7501
|
return i+1; |
|
7502
|
} |
|
7503
|
} |
|
7504
|
pToken->eType = T_ERROR; |
|
7505
|
return i; |
|
7506
|
} |
|
7507
|
case ' ': |
|
7508
|
case '\t': |
|
7509
|
case '\f': |
|
7510
|
case '\r': { |
|
7511
|
for(i=1; (c = z[i])==' ' || c=='\t' || c=='\r' || c=='\f'; i++){} |
|
7512
|
pToken->eType = T_WHITESPACE; |
|
7513
|
return i; |
|
7514
|
} |
|
7515
|
case '#': { |
|
7516
|
for(i=1; (c = z[i])!=0 && c!='\n'; i++){} |
|
7517
|
pToken->eType = T_WHITESPACE; |
|
7518
|
/* If the comment is "#breakpoint" then invoke the pik_breakpoint() |
|
7519
|
** routine. The pik_breakpoint() routie is a no-op that serves as |
|
7520
|
** a convenient place to set a gdb breakpoint when debugging. */ |
|
7521
|
if( strncmp((const char*)z,"#breakpoint",11)==0 ) pik_breakpoint(z); |
|
7522
|
return i; |
|
7523
|
} |
|
7524
|
case '/': { |
|
7525
|
if( z[1]=='*' ){ |
|
7526
|
for(i=2; z[i]!=0 && (z[i]!='*' || z[i+1]!='/'); i++){} |
|
7527
|
if( z[i]=='*' ){ |
|
7528
|
pToken->eType = T_WHITESPACE; |
|
7529
|
return i+2; |
|
7530
|
}else{ |
|
7531
|
pToken->eType = T_ERROR; |
|
7532
|
return i; |
|
7533
|
} |
|
7534
|
}else if( z[1]=='/' ){ |
|
7535
|
for(i=2; z[i]!=0 && z[i]!='\n'; i++){} |
|
7536
|
pToken->eType = T_WHITESPACE; |
|
7537
|
return i; |
|
7538
|
}else if( z[1]=='=' ){ |
|
7539
|
pToken->eType = T_ASSIGN; |
|
7540
|
pToken->eCode = T_SLASH; |
|
7541
|
return 2; |
|
7542
|
}else{ |
|
7543
|
pToken->eType = T_SLASH; |
|
7544
|
return 1; |
|
7545
|
} |
|
7546
|
} |
|
7547
|
case '+': { |
|
7548
|
if( z[1]=='=' ){ |
|
7549
|
pToken->eType = T_ASSIGN; |
|
7550
|
pToken->eCode = T_PLUS; |
|
7551
|
return 2; |
|
7552
|
} |
|
7553
|
pToken->eType = T_PLUS; |
|
7554
|
return 1; |
|
7555
|
} |
|
7556
|
case '*': { |
|
7557
|
if( z[1]=='=' ){ |
|
7558
|
pToken->eType = T_ASSIGN; |
|
7559
|
pToken->eCode = T_STAR; |
|
7560
|
return 2; |
|
7561
|
} |
|
7562
|
pToken->eType = T_STAR; |
|
7563
|
return 1; |
|
7564
|
} |
|
7565
|
case '%': { pToken->eType = T_PERCENT; return 1; } |
|
7566
|
case '(': { pToken->eType = T_LP; return 1; } |
|
7567
|
case ')': { pToken->eType = T_RP; return 1; } |
|
7568
|
case '[': { pToken->eType = T_LB; return 1; } |
|
7569
|
case ']': { pToken->eType = T_RB; return 1; } |
|
7570
|
case ',': { pToken->eType = T_COMMA; return 1; } |
|
7571
|
case ':': { pToken->eType = T_COLON; return 1; } |
|
7572
|
case '>': { pToken->eType = T_GT; return 1; } |
|
7573
|
case '=': { |
|
7574
|
if( z[1]=='=' ){ |
|
7575
|
pToken->eType = T_EQ; |
|
7576
|
return 2; |
|
7577
|
} |
|
7578
|
pToken->eType = T_ASSIGN; |
|
7579
|
pToken->eCode = T_ASSIGN; |
|
7580
|
return 1; |
|
7581
|
} |
|
7582
|
case '-': { |
|
7583
|
if( z[1]=='>' ){ |
|
7584
|
pToken->eType = T_RARROW; |
|
7585
|
return 2; |
|
7586
|
}else if( z[1]=='=' ){ |
|
7587
|
pToken->eType = T_ASSIGN; |
|
7588
|
pToken->eCode = T_MINUS; |
|
7589
|
return 2; |
|
7590
|
}else{ |
|
7591
|
pToken->eType = T_MINUS; |
|
7592
|
return 1; |
|
7593
|
} |
|
7594
|
} |
|
7595
|
case '<': { |
|
7596
|
if( z[1]=='-' ){ |
|
7597
|
if( z[2]=='>' ){ |
|
7598
|
pToken->eType = T_LRARROW; |
|
7599
|
return 3; |
|
7600
|
}else{ |
|
7601
|
pToken->eType = T_LARROW; |
|
7602
|
return 2; |
|
7603
|
} |
|
7604
|
}else{ |
|
7605
|
pToken->eType = T_LT; |
|
7606
|
return 1; |
|
7607
|
} |
|
7608
|
} |
|
7609
|
case 0xe2: { |
|
7610
|
if( z[1]==0x86 ){ |
|
7611
|
if( z[2]==0x90 ){ |
|
7612
|
pToken->eType = T_LARROW; /* <- */ |
|
7613
|
return 3; |
|
7614
|
} |
|
7615
|
if( z[2]==0x92 ){ |
|
7616
|
pToken->eType = T_RARROW; /* -> */ |
|
7617
|
return 3; |
|
7618
|
} |
|
7619
|
if( z[2]==0x94 ){ |
|
7620
|
pToken->eType = T_LRARROW; /* <-> */ |
|
7621
|
return 3; |
|
7622
|
} |
|
7623
|
} |
|
7624
|
pToken->eType = T_ERROR; |
|
7625
|
return 1; |
|
7626
|
} |
|
7627
|
case '{': { |
|
7628
|
int len, depth; |
|
7629
|
i = 1; |
|
7630
|
if( bAllowCodeBlock ){ |
|
7631
|
depth = 1; |
|
7632
|
while( z[i] && depth>0 ){ |
|
7633
|
PToken x; |
|
7634
|
x.z = (char*)(z+i); |
|
7635
|
len = pik_token_length(&x, 0); |
|
7636
|
if( len==1 ){ |
|
7637
|
if( z[i]=='{' ) depth++; |
|
7638
|
if( z[i]=='}' ) depth--; |
|
7639
|
} |
|
7640
|
i += len; |
|
7641
|
} |
|
7642
|
}else{ |
|
7643
|
depth = 0; |
|
7644
|
} |
|
7645
|
if( depth ){ |
|
7646
|
pToken->eType = T_ERROR; |
|
7647
|
return 1; |
|
7648
|
} |
|
7649
|
pToken->eType = T_CODEBLOCK; |
|
7650
|
return i; |
|
7651
|
} |
|
7652
|
case '&': { |
|
7653
|
static const struct { |
|
7654
|
int nByte; /* Number of bytes in zEntity */ |
|
7655
|
int eCode; /* Corresponding token code */ |
|
7656
|
const char *zEntity; /* Name of the HTML entity */ |
|
7657
|
} aEntity[] = { |
|
7658
|
/* 123456789 1234567 */ |
|
7659
|
{ 6, T_RARROW, "→" }, /* Same as -> */ |
|
7660
|
{ 12, T_RARROW, "→" }, /* Same as -> */ |
|
7661
|
{ 6, T_LARROW, "←" }, /* Same as <- */ |
|
7662
|
{ 11, T_LARROW, "←" }, /* Same as <- */ |
|
7663
|
{ 16, T_LRARROW, "↔" }, /* Same as <-> */ |
|
7664
|
}; |
|
7665
|
unsigned int i; |
|
7666
|
for(i=0; i<sizeof(aEntity)/sizeof(aEntity[0]); i++){ |
|
7667
|
if( strncmp((const char*)z,aEntity[i].zEntity,aEntity[i].nByte)==0 ){ |
|
7668
|
pToken->eType = aEntity[i].eCode; |
|
7669
|
return aEntity[i].nByte; |
|
7670
|
} |
|
7671
|
} |
|
7672
|
pToken->eType = T_ERROR; |
|
7673
|
return 1; |
|
7674
|
} |
|
7675
|
default: { |
|
7676
|
c = z[0]; |
|
7677
|
if( c=='.' ){ |
|
7678
|
unsigned char c1 = z[1]; |
|
7679
|
if( IsLower(c1) ){ |
|
7680
|
const PikWord *pFound; |
|
7681
|
for(i=2; (c = z[i])>='a' && c<='z'; i++){} |
|
7682
|
pFound = pik_find_word((const char*)z+1, i-1, |
|
7683
|
pik_keywords, count(pik_keywords)); |
|
7684
|
if( pFound && (pFound->eEdge>0 || |
|
7685
|
pFound->eType==T_EDGEPT || |
|
7686
|
pFound->eType==T_START || |
|
7687
|
pFound->eType==T_END ) |
|
7688
|
){ |
|
7689
|
/* Dot followed by something that is a 2-D place value */ |
|
7690
|
pToken->eType = T_DOT_E; |
|
7691
|
}else if( pFound && (pFound->eType==T_X || pFound->eType==T_Y) ){ |
|
7692
|
/* Dot followed by "x" or "y" */ |
|
7693
|
pToken->eType = T_DOT_XY; |
|
7694
|
}else{ |
|
7695
|
/* Any other "dot" */ |
|
7696
|
pToken->eType = T_DOT_L; |
|
7697
|
} |
|
7698
|
return 1; |
|
7699
|
}else if( IsDigit(c1) ){ |
|
7700
|
i = 0; |
|
7701
|
/* no-op. Fall through to number handling */ |
|
7702
|
}else if( IsUpper(c1) ){ |
|
7703
|
for(i=2; (c = z[i])!=0 && (IsAlnum(c) || c=='_'); i++){} |
|
7704
|
pToken->eType = T_DOT_U; |
|
7705
|
return 1; |
|
7706
|
}else{ |
|
7707
|
pToken->eType = T_ERROR; |
|
7708
|
return 1; |
|
7709
|
} |
|
7710
|
} |
|
7711
|
if( (c>='0' && c<='9') || c=='.' ){ |
|
7712
|
int nDigit; |
|
7713
|
int isInt = 1; |
|
7714
|
if( c!='.' ){ |
|
7715
|
nDigit = 1; |
|
7716
|
for(i=1; (c = z[i])>='0' && c<='9'; i++){ nDigit++; } |
|
7717
|
if( i==1 && (c=='x' || c=='X') ){ |
|
7718
|
for(i=2; (c = z[i])!=0 && IsXDigit(c); i++){} |
|
7719
|
pToken->eType = T_NUMBER; |
|
7720
|
return i; |
|
7721
|
} |
|
7722
|
}else{ |
|
7723
|
isInt = 0; |
|
7724
|
nDigit = 0; |
|
7725
|
i = 0; |
|
7726
|
} |
|
7727
|
if( c=='.' ){ |
|
7728
|
isInt = 0; |
|
7729
|
for(i++; (c = z[i])>='0' && c<='9'; i++){ nDigit++; } |
|
7730
|
} |
|
7731
|
if( nDigit==0 ){ |
|
7732
|
pToken->eType = T_ERROR; |
|
7733
|
return i; |
|
7734
|
} |
|
7735
|
if( c=='e' || c=='E' ){ |
|
7736
|
int iBefore = i; |
|
7737
|
i++; |
|
7738
|
c2 = z[i]; |
|
7739
|
if( c2=='+' || c2=='-' ){ |
|
7740
|
i++; |
|
7741
|
c2 = z[i]; |
|
7742
|
} |
|
7743
|
if( c2<'0' || c>'9' ){ |
|
7744
|
/* This is not an exp */ |
|
7745
|
i = iBefore; |
|
7746
|
}else{ |
|
7747
|
i++; |
|
7748
|
isInt = 0; |
|
7749
|
while( (c = z[i])>='0' && c<='9' ){ i++; } |
|
7750
|
} |
|
7751
|
} |
|
7752
|
c2 = c ? z[i+1] : 0; |
|
7753
|
if( isInt ){ |
|
7754
|
if( (c=='t' && c2=='h') |
|
7755
|
|| (c=='r' && c2=='d') |
|
7756
|
|| (c=='n' && c2=='d') |
|
7757
|
|| (c=='s' && c2=='t') |
|
7758
|
){ |
|
7759
|
pToken->eType = T_NTH; |
|
7760
|
return i+2; |
|
7761
|
} |
|
7762
|
} |
|
7763
|
if( (c=='i' && c2=='n') |
|
7764
|
|| (c=='c' && c2=='m') |
|
7765
|
|| (c=='m' && c2=='m') |
|
7766
|
|| (c=='p' && c2=='t') |
|
7767
|
|| (c=='p' && c2=='x') |
|
7768
|
|| (c=='p' && c2=='c') |
|
7769
|
){ |
|
7770
|
i += 2; |
|
7771
|
} |
|
7772
|
pToken->eType = T_NUMBER; |
|
7773
|
return i; |
|
7774
|
}else if( IsLower(c) ){ |
|
7775
|
const PikWord *pFound; |
|
7776
|
for(i=1; (c = z[i])!=0 && (IsAlnum(c) || c=='_'); i++){} |
|
7777
|
pFound = pik_find_word((const char*)z, i, |
|
7778
|
pik_keywords, count(pik_keywords)); |
|
7779
|
if( pFound ){ |
|
7780
|
pToken->eType = pFound->eType; |
|
7781
|
pToken->eCode = pFound->eCode; |
|
7782
|
pToken->eEdge = pFound->eEdge; |
|
7783
|
return i; |
|
7784
|
} |
|
7785
|
pToken->n = i; |
|
7786
|
if( pik_find_class(pToken)!=0 ){ |
|
7787
|
pToken->eType = T_CLASSNAME; |
|
7788
|
}else{ |
|
7789
|
pToken->eType = T_ID; |
|
7790
|
} |
|
7791
|
return i; |
|
7792
|
}else if( c>='A' && c<='Z' ){ |
|
7793
|
for(i=1; (c = z[i])!=0 && (IsAlnum(c) || c=='_'); i++){} |
|
7794
|
pToken->eType = T_PLACENAME; |
|
7795
|
return i; |
|
7796
|
}else if( c=='$' && z[1]>='1' && z[1]<='9' && !IsDigit(z[2]) ){ |
|
7797
|
pToken->eType = T_PARAMETER; |
|
7798
|
pToken->eCode = z[1] - '1'; |
|
7799
|
return 2; |
|
7800
|
}else if( c=='_' || c=='$' || c=='@' ){ |
|
7801
|
for(i=1; (c = z[i])!=0 && (IsAlnum(c) || c=='_'); i++){} |
|
7802
|
pToken->eType = T_ID; |
|
7803
|
return i; |
|
7804
|
}else{ |
|
7805
|
pToken->eType = T_ERROR; |
|
7806
|
return 1; |
|
7807
|
} |
|
7808
|
} |
|
7809
|
} |
|
7810
|
} |
|
7811
|
|
|
7812
|
/* |
|
7813
|
** Return a pointer to the next non-whitespace token after pThis. |
|
7814
|
** This is used to help form error messages. |
|
7815
|
*/ |
|
7816
|
static PToken pik_next_semantic_token(PToken *pThis){ |
|
7817
|
PToken x; |
|
7818
|
int sz; |
|
7819
|
int i = pThis->n; |
|
7820
|
memset(&x, 0, sizeof(x)); |
|
7821
|
x.z = pThis->z; |
|
7822
|
while(1){ |
|
7823
|
x.z = pThis->z + i; |
|
7824
|
sz = pik_token_length(&x, 1); |
|
7825
|
if( x.eType!=T_WHITESPACE ){ |
|
7826
|
x.n = sz; |
|
7827
|
return x; |
|
7828
|
} |
|
7829
|
i += sz; |
|
7830
|
} |
|
7831
|
} |
|
7832
|
|
|
7833
|
/* Parser arguments to a macro invocation |
|
7834
|
** |
|
7835
|
** (arg1, arg2, ...) |
|
7836
|
** |
|
7837
|
** Arguments are comma-separated, except that commas within string |
|
7838
|
** literals or with (...), {...}, or [...] do not count. The argument |
|
7839
|
** list begins and ends with parentheses. There can be at most 9 |
|
7840
|
** arguments. |
|
7841
|
** |
|
7842
|
** Return the number of bytes in the argument list. |
|
7843
|
*/ |
|
7844
|
static unsigned int pik_parse_macro_args( |
|
7845
|
Pik *p, |
|
7846
|
const char *z, /* Start of the argument list */ |
|
7847
|
int n, /* Available bytes */ |
|
7848
|
PToken *args, /* Fill in with the arguments */ |
|
7849
|
PToken *pOuter /* Arguments of the next outer context, or NULL */ |
|
7850
|
){ |
|
7851
|
int nArg = 0; |
|
7852
|
int i, j, sz; |
|
7853
|
int iStart; |
|
7854
|
int depth = 0; |
|
7855
|
PToken x; |
|
7856
|
if( z[0]!='(' ) return 0; |
|
7857
|
args[0].z = z+1; |
|
7858
|
iStart = 1; |
|
7859
|
for(i=1; i<n && z[i]!=')'; i+=sz){ |
|
7860
|
x.z = z+i; |
|
7861
|
sz = pik_token_length(&x, 0); |
|
7862
|
if( sz!=1 ) continue; |
|
7863
|
if( z[i]==',' && depth<=0 ){ |
|
7864
|
args[nArg].n = i - iStart; |
|
7865
|
if( nArg==8 ){ |
|
7866
|
x.z = z; |
|
7867
|
x.n = 1; |
|
7868
|
pik_error(p, &x, "too many macro arguments - max 9"); |
|
7869
|
return 0; |
|
7870
|
} |
|
7871
|
nArg++; |
|
7872
|
args[nArg].z = z+i+1; |
|
7873
|
iStart = i+1; |
|
7874
|
depth = 0; |
|
7875
|
}else if( z[i]=='(' || z[i]=='{' || z[i]=='[' ){ |
|
7876
|
depth++; |
|
7877
|
}else if( z[i]==')' || z[i]=='}' || z[i]==']' ){ |
|
7878
|
depth--; |
|
7879
|
} |
|
7880
|
} |
|
7881
|
if( z[i]==')' ){ |
|
7882
|
args[nArg].n = i - iStart; |
|
7883
|
/* Remove leading and trailing whitespace from each argument (including |
|
7884
|
** backslash-escaped newlines). If what remains is one of $1, $2, ... $9 |
|
7885
|
** then transfer the corresponding argument from the outer context */ |
|
7886
|
for(j=0; j<=nArg; j++){ |
|
7887
|
PToken *t = &args[j]; |
|
7888
|
while( (t->n>0 && IsSpace(t->z[0])) |
|
7889
|
|| (t->n>1 && t->z[0]=='\\' && IsSpace(t->z[1])) |
|
7890
|
){ |
|
7891
|
t->z++; |
|
7892
|
t->n--; |
|
7893
|
} |
|
7894
|
while( t->n>0 && IsSpace(t->z[t->n-1]) ){ |
|
7895
|
t->n--; |
|
7896
|
if( t->n>0 && t->z[t->n-1]=='\\' ) t->n--; |
|
7897
|
} |
|
7898
|
if( t->n==2 && t->z[0]=='$' && t->z[1]>='1' && t->z[1]<='9' ){ |
|
7899
|
if( pOuter ) *t = pOuter[t->z[1]-'1']; |
|
7900
|
else t->n = 0; |
|
7901
|
} |
|
7902
|
} |
|
7903
|
return i+1; |
|
7904
|
} |
|
7905
|
x.z = z; |
|
7906
|
x.n = 1; |
|
7907
|
pik_error(p, &x, "unterminated macro argument list"); |
|
7908
|
return 0; |
|
7909
|
} |
|
7910
|
|
|
7911
|
/* |
|
7912
|
** Split up the content of a PToken into multiple tokens and |
|
7913
|
** send each to the parser. |
|
7914
|
*/ |
|
7915
|
void pik_tokenize(Pik *p, PToken *pIn, yyParser *pParser, PToken *aParam){ |
|
7916
|
unsigned int i; |
|
7917
|
int sz = 0; |
|
7918
|
PToken token; |
|
7919
|
PMacro *pMac; |
|
7920
|
for(i=0; i<pIn->n && pIn->z[i] && p->nErr==0; i+=sz){ |
|
7921
|
token.eCode = 0; |
|
7922
|
token.eEdge = 0; |
|
7923
|
token.z = pIn->z + i; |
|
7924
|
sz = pik_token_length(&token, 1); |
|
7925
|
if( token.eType==T_WHITESPACE ){ |
|
7926
|
/* no-op */ |
|
7927
|
}else if( sz>50000 ){ |
|
7928
|
token.n = 1; |
|
7929
|
pik_error(p, &token, "token is too long - max length 50000 bytes"); |
|
7930
|
break; |
|
7931
|
}else if( token.eType==T_ERROR ){ |
|
7932
|
token.n = (unsigned short)(sz & 0xffff); |
|
7933
|
pik_error(p, &token, "unrecognized token"); |
|
7934
|
break; |
|
7935
|
}else if( sz+i>pIn->n ){ |
|
7936
|
token.n = pIn->n - i; |
|
7937
|
pik_error(p, &token, "syntax error"); |
|
7938
|
break; |
|
7939
|
}else if( token.eType==T_PARAMETER ){ |
|
7940
|
/* Substitute a parameter into the input stream */ |
|
7941
|
if( aParam==0 || aParam[token.eCode].n==0 ){ |
|
7942
|
continue; |
|
7943
|
} |
|
7944
|
token.n = (unsigned short)(sz & 0xffff); |
|
7945
|
if( p->nCtx>=count(p->aCtx) ){ |
|
7946
|
pik_error(p, &token, "macros nested too deep"); |
|
7947
|
}else{ |
|
7948
|
p->aCtx[p->nCtx++] = token; |
|
7949
|
pik_tokenize(p, &aParam[token.eCode], pParser, 0); |
|
7950
|
p->nCtx--; |
|
7951
|
} |
|
7952
|
}else if( token.eType==T_ID |
|
7953
|
&& (token.n = (unsigned short)(sz & 0xffff), |
|
7954
|
(pMac = pik_find_macro(p,&token))!=0) |
|
7955
|
){ |
|
7956
|
PToken args[9]; |
|
7957
|
unsigned int j = i+sz; |
|
7958
|
if( pMac->inUse ){ |
|
7959
|
pik_error(p, &pMac->macroName, "recursive macro definition"); |
|
7960
|
break; |
|
7961
|
} |
|
7962
|
token.n = (short int)(sz & 0xffff); |
|
7963
|
if( p->nCtx>=count(p->aCtx) ){ |
|
7964
|
pik_error(p, &token, "macros nested too deep"); |
|
7965
|
break; |
|
7966
|
} |
|
7967
|
pMac->inUse = 1; |
|
7968
|
memset(args, 0, sizeof(args)); |
|
7969
|
p->aCtx[p->nCtx++] = token; |
|
7970
|
sz += pik_parse_macro_args(p, pIn->z+j, pIn->n-j, args, aParam); |
|
7971
|
pik_tokenize(p, &pMac->macroBody, pParser, args); |
|
7972
|
p->nCtx--; |
|
7973
|
pMac->inUse = 0; |
|
7974
|
}else{ |
|
7975
|
#if 0 |
|
7976
|
printf("******** Token %s (%d): \"%.*s\" **************\n", |
|
7977
|
yyTokenName[token.eType], token.eType, |
|
7978
|
(int)(IsSpace(token.z[0]) ? 0 : sz), token.z); |
|
7979
|
#endif |
|
7980
|
token.n = (unsigned short)(sz & 0xffff); |
|
7981
|
if( p->nToken++ > PIKCHR_TOKEN_LIMIT ){ |
|
7982
|
pik_error(p, &token, "script is too complex"); |
|
7983
|
break; |
|
7984
|
} |
|
7985
|
if( token.eType==T_ISODATE ){ |
|
7986
|
token.z = "\"" MANIFEST_ISODATE "\""; |
|
7987
|
token.n = sizeof(MANIFEST_ISODATE)+1; |
|
7988
|
token.eType = T_STRING; |
|
7989
|
} |
|
7990
|
pik_parser(pParser, token.eType, token); |
|
7991
|
} |
|
7992
|
} |
|
7993
|
} |
|
7994
|
|
|
7995
|
/* |
|
7996
|
** Return the version name. |
|
7997
|
*/ |
|
7998
|
const char *pikchr_version(void) |
|
7999
|
/* Emscripten workaround, else it chokes on the inlined version */; |
|
8000
|
|
|
8001
|
const char *pikchr_version(void){ |
|
8002
|
return RELEASE_VERSION " " MANIFEST_ISODATE; |
|
8003
|
} |
|
8004
|
|
|
8005
|
/* |
|
8006
|
** Parse the PIKCHR script contained in zText[]. Return a rendering. Or |
|
8007
|
** if an error is encountered, return the error text. The error message |
|
8008
|
** is HTML formatted. So regardless of what happens, the return text |
|
8009
|
** is safe to be insertd into an HTML output stream. |
|
8010
|
** |
|
8011
|
** If pnWidth and pnHeight are not NULL, then this routine writes the |
|
8012
|
** width and height of the <SVG> object into the integers that they |
|
8013
|
** point to. A value of -1 is written if an error is seen. |
|
8014
|
** |
|
8015
|
** If zClass is not NULL, then it is a class name to be included in |
|
8016
|
** the <SVG> markup. |
|
8017
|
** |
|
8018
|
** The returned string is contained in memory obtained from malloc() |
|
8019
|
** and should be released by the caller. |
|
8020
|
*/ |
|
8021
|
char *pikchr( |
|
8022
|
const char *zText, /* Input PIKCHR source text. zero-terminated */ |
|
8023
|
const char *zClass, /* Add class="%s" to <svg> markup */ |
|
8024
|
unsigned int mFlags, /* Flags used to influence rendering behavior */ |
|
8025
|
int *pnWidth, /* Write width of <svg> here, if not NULL */ |
|
8026
|
int *pnHeight /* Write height here, if not NULL */ |
|
8027
|
){ |
|
8028
|
Pik s; |
|
8029
|
yyParser sParse; |
|
8030
|
|
|
8031
|
memset(&s, 0, sizeof(s)); |
|
8032
|
s.sIn.z = zText; |
|
8033
|
s.sIn.n = (unsigned int)strlen(zText); |
|
8034
|
s.eDir = DIR_RIGHT; |
|
8035
|
s.zClass = zClass; |
|
8036
|
s.mFlags = mFlags; |
|
8037
|
pik_parserInit(&sParse, &s); |
|
8038
|
#if 0 |
|
8039
|
pik_parserTrace(stdout, "parser: "); |
|
8040
|
#endif |
|
8041
|
pik_tokenize(&s, &s.sIn, &sParse, 0); |
|
8042
|
if( s.nErr==0 ){ |
|
8043
|
PToken token; |
|
8044
|
memset(&token,0,sizeof(token)); |
|
8045
|
token.z = zText + (s.sIn.n>0 ? s.sIn.n-1 : 0); |
|
8046
|
token.n = 1; |
|
8047
|
pik_parser(&sParse, 0, token); |
|
8048
|
} |
|
8049
|
pik_parserFinalize(&sParse); |
|
8050
|
if( s.zOut==0 && s.nErr==0 ){ |
|
8051
|
pik_append(&s, "<!-- empty pikchr diagram -->\n", -1); |
|
8052
|
} |
|
8053
|
while( s.pVar ){ |
|
8054
|
PVar *pNext = s.pVar->pNext; |
|
8055
|
free(s.pVar); |
|
8056
|
s.pVar = pNext; |
|
8057
|
} |
|
8058
|
while( s.pMacros ){ |
|
8059
|
PMacro *pNext = s.pMacros->pNext; |
|
8060
|
free(s.pMacros); |
|
8061
|
s.pMacros = pNext; |
|
8062
|
} |
|
8063
|
if( pnWidth ) *pnWidth = s.nErr ? -1 : s.wSVG; |
|
8064
|
if( pnHeight ) *pnHeight = s.nErr ? -1 : s.hSVG; |
|
8065
|
if( s.zOut ){ |
|
8066
|
s.zOut[s.nOut] = 0; |
|
8067
|
s.zOut = realloc(s.zOut, s.nOut+1); |
|
8068
|
} |
|
8069
|
return s.zOut; |
|
8070
|
} |
|
8071
|
|
|
8072
|
#if defined(PIKCHR_FUZZ) |
|
8073
|
#include <stdint.h> |
|
8074
|
int LLVMFuzzerTestOneInput(const uint8_t *aData, size_t nByte){ |
|
8075
|
int w,h; |
|
8076
|
char *zIn, *zOut; |
|
8077
|
unsigned int mFlags = nByte & 3; |
|
8078
|
zIn = malloc( nByte + 1 ); |
|
8079
|
if( zIn==0 ) return 0; |
|
8080
|
memcpy(zIn, aData, nByte); |
|
8081
|
zIn[nByte] = 0; |
|
8082
|
zOut = pikchr(zIn, "pikchr", mFlags, &w, &h); |
|
8083
|
free(zIn); |
|
8084
|
free(zOut); |
|
8085
|
return 0; |
|
8086
|
} |
|
8087
|
#endif /* PIKCHR_FUZZ */ |
|
8088
|
|
|
8089
|
#if defined(PIKCHR_SHELL) |
|
8090
|
/* Print a usage comment for the shell and exit. */ |
|
8091
|
static void usage(const char *argv0){ |
|
8092
|
fprintf(stderr, "usage: %s [OPTIONS] FILE ...\n", argv0); |
|
8093
|
fprintf(stderr, |
|
8094
|
"Convert Pikchr input files into SVG. Filename \"-\" means stdin.\n" |
|
8095
|
"All output goes to stdout.\n" |
|
8096
|
"Options:\n" |
|
8097
|
" --dark-mode Generate \"dark mode\" output\n" |
|
8098
|
" --dont-stop Process all files even if earlier files have errors\n" |
|
8099
|
" --svg-only Emit raw SVG without the HTML wrapper\n" |
|
8100
|
); |
|
8101
|
exit(1); |
|
8102
|
} |
|
8103
|
|
|
8104
|
/* Send text to standard output, but escape HTML markup */ |
|
8105
|
static void print_escape_html(const char *z){ |
|
8106
|
int j; |
|
8107
|
char c; |
|
8108
|
while( z[0]!=0 ){ |
|
8109
|
for(j=0; (c = z[j])!=0 && c!='<' && c!='>' && c!='&'; j++){} |
|
8110
|
if( j ) printf("%.*s", j, z); |
|
8111
|
z += j+1; |
|
8112
|
j = -1; |
|
8113
|
if( c=='<' ){ |
|
8114
|
printf("<"); |
|
8115
|
}else if( c=='>' ){ |
|
8116
|
printf(">"); |
|
8117
|
}else if( c=='&' ){ |
|
8118
|
printf("&"); |
|
8119
|
}else if( c==0 ){ |
|
8120
|
break; |
|
8121
|
} |
|
8122
|
} |
|
8123
|
} |
|
8124
|
|
|
8125
|
/* Read the content of file zFilename into memory obtained from malloc() |
|
8126
|
** Return the memory. If something goes wrong (ex: the file does not exist |
|
8127
|
** or cannot be opened) put an error message on stderr and return NULL. |
|
8128
|
** |
|
8129
|
** If the filename is "-" read stdin. |
|
8130
|
*/ |
|
8131
|
static char *readFile(const char *zFilename){ |
|
8132
|
FILE *in; |
|
8133
|
size_t n; |
|
8134
|
size_t nUsed = 0; |
|
8135
|
size_t nAlloc = 0; |
|
8136
|
char *z = 0, *zNew = 0; |
|
8137
|
in = strcmp(zFilename,"-")==0 ? stdin : fopen(zFilename, "rb"); |
|
8138
|
if( in==0 ){ |
|
8139
|
fprintf(stderr, "cannot open \"%s\" for reading\n", zFilename); |
|
8140
|
return 0; |
|
8141
|
} |
|
8142
|
while(1){ |
|
8143
|
if( nUsed+2>=nAlloc ){ |
|
8144
|
nAlloc = nAlloc*2 + 4000; |
|
8145
|
zNew = realloc(z, nAlloc); |
|
8146
|
} |
|
8147
|
if( zNew==0 ){ |
|
8148
|
free(z); |
|
8149
|
fprintf(stderr, "out of memory trying to allocate %lld bytes\n", |
|
8150
|
(long long int)nAlloc); |
|
8151
|
exit(1); |
|
8152
|
} |
|
8153
|
z = zNew; |
|
8154
|
n = fread(z+nUsed, 1, nAlloc-nUsed-1, in); |
|
8155
|
if( n<=0 ){ |
|
8156
|
break; |
|
8157
|
} |
|
8158
|
nUsed += n; |
|
8159
|
} |
|
8160
|
if( in!=stdin ) fclose(in); |
|
8161
|
z[nUsed] = 0; |
|
8162
|
return z; |
|
8163
|
} |
|
8164
|
|
|
8165
|
|
|
8166
|
/* Testing interface |
|
8167
|
** |
|
8168
|
** Generate HTML on standard output that displays both the original |
|
8169
|
** input text and the rendered SVG for all files named on the command |
|
8170
|
** line. |
|
8171
|
*/ |
|
8172
|
int main(int argc, char **argv){ |
|
8173
|
int i; |
|
8174
|
int bSvgOnly = 0; /* Output SVG only. No HTML wrapper */ |
|
8175
|
int bDontStop = 0; /* Continue in spite of errors */ |
|
8176
|
int exitCode = 0; /* What to return */ |
|
8177
|
int mFlags = 0; /* mFlags argument to pikchr() */ |
|
8178
|
const char *zStyle = ""; /* Extra styling */ |
|
8179
|
const char *zHtmlHdr = |
|
8180
|
"<!DOCTYPE html>\n" |
|
8181
|
"<html lang=\"en-US\">\n" |
|
8182
|
"<head>\n<title>PIKCHR Test</title>\n" |
|
8183
|
"<style>\n" |
|
8184
|
" .hidden {\n" |
|
8185
|
" position: absolute !important;\n" |
|
8186
|
" opacity: 0 !important;\n" |
|
8187
|
" pointer-events: none !important;\n" |
|
8188
|
" display: none !important;\n" |
|
8189
|
" }\n" |
|
8190
|
"</style>\n" |
|
8191
|
"<script>\n" |
|
8192
|
" function toggleHidden(id){\n" |
|
8193
|
" for(var c of document.getElementById(id).children){\n" |
|
8194
|
" c.classList.toggle('hidden');\n" |
|
8195
|
" }\n" |
|
8196
|
" }\n" |
|
8197
|
"</script>\n" |
|
8198
|
"<meta charset=\"utf-8\">\n" |
|
8199
|
"</head>\n" |
|
8200
|
"<body>\n" |
|
8201
|
; |
|
8202
|
if( argc<2 ) usage(argv[0]); |
|
8203
|
for(i=1; i<argc; i++){ |
|
8204
|
char *zIn; |
|
8205
|
char *zOut; |
|
8206
|
int w, h; |
|
8207
|
|
|
8208
|
if( argv[i][0]=='-' && argv[i][1]!=0 ){ |
|
8209
|
char *z = argv[i]; |
|
8210
|
z++; |
|
8211
|
if( z[0]=='-' ) z++; |
|
8212
|
if( strcmp(z,"dont-stop")==0 ){ |
|
8213
|
bDontStop = 1; |
|
8214
|
}else |
|
8215
|
if( strcmp(z,"dark-mode")==0 ){ |
|
8216
|
zStyle = "color:white;background-color:black;"; |
|
8217
|
mFlags |= PIKCHR_DARK_MODE; |
|
8218
|
}else |
|
8219
|
if( strcmp(z,"svg-only")==0 ){ |
|
8220
|
if( zHtmlHdr==0 ){ |
|
8221
|
fprintf(stderr, "the \"%s\" option must come first\n",argv[i]); |
|
8222
|
exit(1); |
|
8223
|
} |
|
8224
|
bSvgOnly = 1; |
|
8225
|
mFlags |= PIKCHR_PLAINTEXT_ERRORS; |
|
8226
|
}else |
|
8227
|
if( strcmp(z,"version")==0 || strcmp(z,"v")==0 ){ |
|
8228
|
printf("pikchr %s\n", pikchr_version()); |
|
8229
|
return 0; |
|
8230
|
}else |
|
8231
|
{ |
|
8232
|
fprintf(stderr,"unknown option: \"%s\"\n", argv[i]); |
|
8233
|
usage(argv[0]); |
|
8234
|
} |
|
8235
|
continue; |
|
8236
|
} |
|
8237
|
zIn = readFile(argv[i]); |
|
8238
|
if( zIn==0 ) continue; |
|
8239
|
zOut = pikchr(zIn, "pikchr", mFlags, &w, &h); |
|
8240
|
if( w<0 && !bDontStop ) exitCode = 1; |
|
8241
|
if( zOut==0 ){ |
|
8242
|
fprintf(stderr, "pikchr() returns NULL. Out of memory?\n"); |
|
8243
|
if( !bDontStop ) exit(1); |
|
8244
|
}else if( bSvgOnly ){ |
|
8245
|
printf("%s\n", zOut); |
|
8246
|
}else{ |
|
8247
|
if( zHtmlHdr ){ |
|
8248
|
printf("%s", zHtmlHdr); |
|
8249
|
zHtmlHdr = 0; |
|
8250
|
} |
|
8251
|
printf("<h1>File %s</h1>\n", argv[i]); |
|
8252
|
if( w<0 ){ |
|
8253
|
printf("<p>ERROR</p>\n%s\n", zOut); |
|
8254
|
}else{ |
|
8255
|
printf("<div id=\"svg-%d\" onclick=\"toggleHidden('svg-%d')\">\n",i,i); |
|
8256
|
printf("<div style='border:3px solid lightgray;max-width:%dpx;%s'>\n", |
|
8257
|
w,zStyle); |
|
8258
|
printf("%s</div>\n", zOut); |
|
8259
|
printf("<pre class='hidden'>"); |
|
8260
|
print_escape_html(zIn); |
|
8261
|
printf("</pre>\n</div>\n"); |
|
8262
|
} |
|
8263
|
} |
|
8264
|
free(zOut); |
|
8265
|
free(zIn); |
|
8266
|
} |
|
8267
|
if( !bSvgOnly ){ |
|
8268
|
printf("</body></html>\n"); |
|
8269
|
} |
|
8270
|
return exitCode ? EXIT_FAILURE : EXIT_SUCCESS; |
|
8271
|
} |
|
8272
|
#endif /* PIKCHR_SHELL */ |
|
8273
|
|
|
8274
|
#ifdef PIKCHR_TCL |
|
8275
|
#include <tcl.h> |
|
8276
|
/* Compatability between Tcl8.6 and Tcl9.0 */ |
|
8277
|
#if TCL_MAJOR_VERSION==9 |
|
8278
|
# define CONST const |
|
8279
|
#elif !defined(Tcl_Size) |
|
8280
|
typedef int Tcl_Size; |
|
8281
|
#endif |
|
8282
|
|
|
8283
|
/* |
|
8284
|
** An interface to TCL |
|
8285
|
** |
|
8286
|
** TCL command: pikchr $INPUTTEXT |
|
8287
|
** |
|
8288
|
** Returns a list of 3 elements which are the output text, the width, and |
|
8289
|
** the height. |
|
8290
|
** |
|
8291
|
** Register the "pikchr" command by invoking Pikchr_Init(Tcl_Interp*). Or |
|
8292
|
** compile this source file as a shared library and load it using the |
|
8293
|
** "load" command of Tcl. |
|
8294
|
** |
|
8295
|
** Compile this source-code file into a shared library using a command |
|
8296
|
** similar to this: |
|
8297
|
** |
|
8298
|
** gcc -c pikchr.so -DPIKCHR_TCL -shared pikchr.c |
|
8299
|
*/ |
|
8300
|
static int pik_tcl_command( |
|
8301
|
ClientData clientData, /* Not Used */ |
|
8302
|
Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ |
|
8303
|
int objc, /* Number of arguments */ |
|
8304
|
Tcl_Obj *CONST objv[] /* Command arguments */ |
|
8305
|
){ |
|
8306
|
int w, h; /* Width and height of the pikchr */ |
|
8307
|
const char *zIn; /* Source text input */ |
|
8308
|
char *zOut; /* SVG output text */ |
|
8309
|
Tcl_Obj *pRes; /* The result TCL object */ |
|
8310
|
|
|
8311
|
(void)clientData; |
|
8312
|
if( objc!=2 ){ |
|
8313
|
Tcl_WrongNumArgs(interp, 1, objv, "PIKCHR_SOURCE_TEXT"); |
|
8314
|
return TCL_ERROR; |
|
8315
|
} |
|
8316
|
zIn = Tcl_GetString(objv[1]); |
|
8317
|
w = h = 0; |
|
8318
|
zOut = pikchr(zIn, "pikchr", 0, &w, &h); |
|
8319
|
if( zOut==0 ){ |
|
8320
|
return TCL_ERROR; /* Out of memory */ |
|
8321
|
} |
|
8322
|
pRes = Tcl_NewObj(); |
|
8323
|
Tcl_ListObjAppendElement(0, pRes, Tcl_NewStringObj(zOut, -1)); |
|
8324
|
free(zOut); |
|
8325
|
Tcl_ListObjAppendElement(0, pRes, Tcl_NewIntObj(w)); |
|
8326
|
Tcl_ListObjAppendElement(0, pRes, Tcl_NewIntObj(h)); |
|
8327
|
Tcl_SetObjResult(interp, pRes); |
|
8328
|
return TCL_OK; |
|
8329
|
} |
|
8330
|
|
|
8331
|
#ifndef PACKAGE_NAME |
|
8332
|
# define PACKAGE_NAME "pikchr" |
|
8333
|
#endif |
|
8334
|
#ifndef PACKAGE_VERSION |
|
8335
|
# define PACKAGE_VERSION "1.0" |
|
8336
|
#endif |
|
8337
|
|
|
8338
|
/* Invoke this routine to register the "pikchr" command with the interpreter |
|
8339
|
** given in the argument */ |
|
8340
|
int Pikchr_Init(Tcl_Interp *interp){ |
|
8341
|
Tcl_CreateObjCommand(interp, "pikchr", pik_tcl_command, 0, 0); |
|
8342
|
Tcl_PkgProvide(interp, PACKAGE_NAME, PACKAGE_VERSION); |
|
8343
|
return TCL_OK; |
|
8344
|
} |
|
8345
|
|
|
8346
|
|
|
8347
|
#endif /* PIKCHR_TCL */ |
|
8348
|
|
|
8349
|
|
|
8350
|
#line 8350 "pikchr.c" |
|
8351
|
|