* Got some more parsing in there
[citadel.git] / citadel / parsedate.c
1 #ifndef lint
2 static char yysccsid[] = "@(#)yaccpar   1.9 (Berkeley) 02/21/93";
3 #endif
4 #define YYBYACC 1
5 #define YYMAJOR 1
6 #define YYMINOR 9
7 #define yyclearin (yychar=(-1))
8 #define yyerrok (yyerrflag=0)
9 #define YYRECOVERING (yyerrflag!=0)
10 #define YYPREFIX "yy"
11 #line 2 "parsedate.y"
12 /* $Revision$
13 **
14 **  Originally written by Steven M. Bellovin <smb@research.att.com> while
15 **  at the University of North Carolina at Chapel Hill.  Later tweaked by
16 **  a couple of people on Usenet.  Completely overhauled by Rich $alz
17 **  <rsalz@osf.org> and Jim Berets <jberets@bbn.com> in August, 1990.
18 **  Further revised (removed obsolete constructs and cleaned up timezone
19 **  names) in August, 1991, by Rich.  Paul Eggert <eggert@twinsun.com>
20 **  helped in September, 1992.  Art Cancro <ajc@uncnsrd.mt-kisco.ny.us> cleaned
21 **  it up for ANSI C in December, 1999.
22 **
23 **  This grammar has six shift/reduce conflicts.
24 **
25 **  This code is in the public domain and has no copyright.
26 */
27 /* SUPPRESS 530 *//* Empty body for statement */
28 /* SUPPRESS 593 on yyerrlab *//* Label was not used */
29 /* SUPPRESS 593 on yynewstate *//* Label was not used */
30 /* SUPPRESS 595 on yypvt *//* Automatic variable may be used before set */
31 #include <stdio.h>
32 #include <sys/types.h>
33 #include <ctype.h>
34 #include <time.h>
35 #include "parsedate.h"
36
37 int date_lex(void);
38
39 #define yyparse         date_parse
40 #define yylex           date_lex
41 #define yyerror         date_error
42
43
44     /* See the LeapYears table in Convert. */
45 #define EPOCH           1970
46 #define END_OF_TIME     2038
47     /* Constants for general time calculations. */
48 #define DST_OFFSET      1
49 #define SECSPERDAY      (24L * 60L * 60L)
50     /* Readability for TABLE stuff. */
51 #define HOUR(x)         (x * 60)
52
53 #define LPAREN          '('
54 #define RPAREN          ')'
55 #define IS7BIT(x)       ((unsigned int)(x) < 0200)
56
57 #define SIZEOF(array)   ((int)(sizeof array / sizeof array[0]))
58 #define ENDOF(array)    (&array[SIZEOF(array)])
59
60
61 /*
62 **  An entry in the lexical lookup table.
63 */
64 typedef struct _TABLE {
65     char        *name;
66     int         type;
67     time_t      value;
68 } TABLE;
69
70 /*
71 **  Daylight-savings mode:  on, off, or not yet known.
72 */
73 typedef enum _DSTMODE {
74     DSTon, DSToff, DSTmaybe
75 } DSTMODE;
76
77 /*
78 **  Meridian:  am, pm, or 24-hour style.
79 */
80 typedef enum _MERIDIAN {
81     MERam, MERpm, MER24
82 } MERIDIAN;
83
84
85 /*
86 **  Global variables.  We could get rid of most of them by using a yacc
87 **  union, but this is more efficient.  (This routine predates the
88 **  yacc %union construct.)
89 */
90 static char     *yyInput;
91 static DSTMODE  yyDSTmode;
92 static int      yyHaveDate;
93 static int      yyHaveRel;
94 static int      yyHaveTime;
95 static time_t   yyTimezone;
96 static time_t   yyDay;
97 static time_t   yyHour;
98 static time_t   yyMinutes;
99 static time_t   yyMonth;
100 static time_t   yySeconds;
101 static time_t   yyYear;
102 static MERIDIAN yyMeridian;
103 static time_t   yyRelMonth;
104 static time_t   yyRelSeconds;
105
106
107 static void             date_error(char *);
108 #line 100 "parsedate.y"
109 typedef union {
110     time_t              Number;
111     enum _MERIDIAN      Meridian;
112 } YYSTYPE;
113 #line 114 "y.tab.c"
114 #define tDAY 257
115 #define tDAYZONE 258
116 #define tMERIDIAN 259
117 #define tMONTH 260
118 #define tMONTH_UNIT 261
119 #define tSEC_UNIT 262
120 #define tSNUMBER 263
121 #define tUNUMBER 264
122 #define tZONE 265
123 #define YYERRCODE 256
124 short yylhs[] = {                                        -1,
125     0,    0,    4,    4,    4,    4,    5,    5,    5,    5,
126     5,    2,    2,    2,    2,    1,    6,    6,    6,    6,
127     6,    6,    6,    7,    7,    7,    7,    3,    3,
128 };
129 short yylen[] = {                                         2,
130     0,    2,    1,    2,    1,    1,    2,    4,    4,    6,
131     6,    1,    1,    2,    1,    1,    3,    5,    2,    4,
132     2,    3,    5,    2,    2,    2,    2,    0,    1,
133 };
134 short yydefred[] = {                                      1,
135     0,    0,    0,    0,    0,    2,    0,    5,    6,    0,
136     0,   26,   24,   29,    0,   27,   25,    0,    0,    7,
137    13,   16,    0,   15,    4,    0,    0,   22,    0,    0,
138    14,    0,   20,    0,    9,    8,    0,   23,    0,   18,
139    11,   10,
140 };
141 short yydgoto[] = {                                       1,
142    24,   25,   20,    6,    7,    8,    9,
143 };
144 short yysindex[] = {                                      0,
145  -239,  -36, -248, -255,  -47,    0, -232,    0,    0, -247,
146   -25,    0,    0,    0, -237,    0,    0, -235, -234,    0,
147     0,    0, -231,    0,    0, -226, -229,    0,  -56,  -11,
148     0, -227,    0, -225,    0,    0, -224,    0, -250,    0,
149     0,    0,
150 };
151 short yyrindex[] = {                                      0,
152     0,    0,    0,    0,    1,    0,   22,    0,    0,    0,
153    12,    0,    0,    0,   28,    0,    0,    0,    0,    0,
154     0,    0,   23,    0,    0,    0,    0,    0,    3,   14,
155     0,    0,    0,    0,    0,    0,    0,    0,    3,    0,
156     0,    0,
157 };
158 short yygindex[] = {                                      0,
159   -19,    0,  -24,    0,    0,    0,    0,
160 };
161 #define YYTABLESIZE 291
162 short yytable[] = {                                      19,
163    28,   34,   28,   31,   36,   12,   13,   10,   14,   35,
164    18,   19,   22,   17,   42,   11,   26,    2,   27,   41,
165     3,    3,   12,    4,    5,   21,   28,   21,   29,   30,
166    22,   22,   23,   32,   33,   37,   38,    0,   39,   40,
167     0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
168     0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
169     0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
170     0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
171     0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
172     0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
173     0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
174     0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
175     0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
176     0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
177     0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
178     0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
179     0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
180     0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
181     0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
182     0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
183     0,    0,   14,    0,    0,    0,   22,    0,    0,    0,
184     0,   14,   15,   16,   17,    0,    0,    0,    0,    0,
185     0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
186     0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
187     0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
188     0,    0,    0,    0,    0,    0,    0,   28,   28,   28,
189    28,    0,   28,   28,   28,   28,   28,   28,   19,    0,
190    17,   19,    0,   17,   19,   19,   17,   17,    3,   12,
191     0,    3,   12,    0,   21,    3,   12,   21,    0,    0,
192    21,
193 };
194 short yycheck[] = {                                      47,
195     0,   58,    0,   23,   29,  261,  262,   44,  259,   29,
196    58,    0,  263,    0,   39,  264,  264,  257,   44,   39,
197   260,    0,    0,  263,  264,  258,  264,    0,  264,  264,
198   263,  263,  265,  260,  264,   47,  264,   -1,  264,  264,
199    -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
200    -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
201    -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
202    -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
203    -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
204    -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
205    -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
206    -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
207    -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
208    -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
209    -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
210    -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
211    -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
212    -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
213    -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
214    -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
215    -1,   -1,  259,   -1,   -1,   -1,  263,   -1,   -1,   -1,
216    -1,  259,  260,  261,  262,   -1,   -1,   -1,   -1,   -1,
217    -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
218    -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
219    -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
220    -1,   -1,   -1,   -1,   -1,   -1,   -1,  257,  258,  257,
221   258,   -1,  260,  263,  264,  265,  264,  265,  257,   -1,
222   257,  260,   -1,  260,  263,  264,  263,  264,  257,  257,
223    -1,  260,  260,   -1,  257,  264,  264,  260,   -1,   -1,
224   263,
225 };
226 #define YYFINAL 1
227 #ifndef YYDEBUG
228 #define YYDEBUG 0
229 #endif
230 #define YYMAXTOKEN 265
231 #if YYDEBUG
232 char *yyname[] = {
233 "end-of-file",0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
234 0,0,0,0,0,0,0,0,0,0,"','",0,0,"'/'",0,0,0,0,0,0,0,0,0,0,"':'",0,0,0,0,0,0,0,0,0,
235 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
236 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
237 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
238 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
239 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,"tDAY","tDAYZONE",
240 "tMERIDIAN","tMONTH","tMONTH_UNIT","tSEC_UNIT","tSNUMBER","tUNUMBER","tZONE",
241 };
242 char *yyrule[] = {
243 "$accept : spec",
244 "spec :",
245 "spec : spec item",
246 "item : time",
247 "item : time zone",
248 "item : date",
249 "item : rel",
250 "time : tUNUMBER o_merid",
251 "time : tUNUMBER ':' tUNUMBER o_merid",
252 "time : tUNUMBER ':' tUNUMBER numzone",
253 "time : tUNUMBER ':' tUNUMBER ':' tUNUMBER o_merid",
254 "time : tUNUMBER ':' tUNUMBER ':' tUNUMBER numzone",
255 "zone : tZONE",
256 "zone : tDAYZONE",
257 "zone : tZONE numzone",
258 "zone : numzone",
259 "numzone : tSNUMBER",
260 "date : tUNUMBER '/' tUNUMBER",
261 "date : tUNUMBER '/' tUNUMBER '/' tUNUMBER",
262 "date : tMONTH tUNUMBER",
263 "date : tMONTH tUNUMBER ',' tUNUMBER",
264 "date : tUNUMBER tMONTH",
265 "date : tUNUMBER tMONTH tUNUMBER",
266 "date : tDAY ',' tUNUMBER tMONTH tUNUMBER",
267 "rel : tSNUMBER tSEC_UNIT",
268 "rel : tUNUMBER tSEC_UNIT",
269 "rel : tSNUMBER tMONTH_UNIT",
270 "rel : tUNUMBER tMONTH_UNIT",
271 "o_merid :",
272 "o_merid : tMERIDIAN",
273 };
274 #endif
275 #ifdef YYSTACKSIZE
276 #undef YYMAXDEPTH
277 #define YYMAXDEPTH YYSTACKSIZE
278 #else
279 #ifdef YYMAXDEPTH
280 #define YYSTACKSIZE YYMAXDEPTH
281 #else
282 #define YYSTACKSIZE 500
283 #define YYMAXDEPTH 500
284 #endif
285 #endif
286 int yydebug;
287 int yynerrs;
288 int yyerrflag;
289 int yychar;
290 short *yyssp;
291 YYSTYPE *yyvsp;
292 YYSTYPE yyval;
293 YYSTYPE yylval;
294 short yyss[YYSTACKSIZE];
295 YYSTYPE yyvs[YYSTACKSIZE];
296 #define yystacksize YYSTACKSIZE
297 #line 287 "parsedate.y"
298
299 /* Month and day table. */
300 static TABLE    MonthDayTable[] = {
301     { "january",        tMONTH,  1 },
302     { "february",       tMONTH,  2 },
303     { "march",          tMONTH,  3 },
304     { "april",          tMONTH,  4 },
305     { "may",            tMONTH,  5 },
306     { "june",           tMONTH,  6 },
307     { "july",           tMONTH,  7 },
308     { "august",         tMONTH,  8 },
309     { "september",      tMONTH,  9 },
310     { "october",        tMONTH, 10 },
311     { "november",       tMONTH, 11 },
312     { "december",       tMONTH, 12 },
313         /* The value of the day isn't used... */
314     { "sunday",         tDAY, 0 },
315     { "monday",         tDAY, 0 },
316     { "tuesday",        tDAY, 0 },
317     { "wednesday",      tDAY, 0 },
318     { "thursday",       tDAY, 0 },
319     { "friday",         tDAY, 0 },
320     { "saturday",       tDAY, 0 },
321 };
322
323 /* Time units table. */
324 static TABLE    UnitsTable[] = {
325     { "year",           tMONTH_UNIT,    12 },
326     { "month",          tMONTH_UNIT,    1 },
327     { "week",           tSEC_UNIT,      7L * 24 * 60 * 60 },
328     { "day",            tSEC_UNIT,      1L * 24 * 60 * 60 },
329     { "hour",           tSEC_UNIT,      60 * 60 },
330     { "minute",         tSEC_UNIT,      60 },
331     { "min",            tSEC_UNIT,      60 },
332     { "second",         tSEC_UNIT,      1 },
333     { "sec",            tSEC_UNIT,      1 },
334 };
335
336 /* Timezone table. */
337 static TABLE    TimezoneTable[] = {
338     { "gmt",    tZONE,     HOUR( 0) },  /* Greenwich Mean */
339     { "ut",     tZONE,     HOUR( 0) },  /* Universal */
340     { "utc",    tZONE,     HOUR( 0) },  /* Universal Coordinated */
341     { "cut",    tZONE,     HOUR( 0) },  /* Coordinated Universal */
342     { "z",      tZONE,     HOUR( 0) },  /* Greenwich Mean */
343     { "wet",    tZONE,     HOUR( 0) },  /* Western European */
344     { "bst",    tDAYZONE,  HOUR( 0) },  /* British Summer */
345     { "nst",    tZONE,     HOUR(3)+30 }, /* Newfoundland Standard */
346     { "ndt",    tDAYZONE,  HOUR(3)+30 }, /* Newfoundland Daylight */
347     { "ast",    tZONE,     HOUR( 4) },  /* Atlantic Standard */
348     { "adt",    tDAYZONE,  HOUR( 4) },  /* Atlantic Daylight */
349     { "est",    tZONE,     HOUR( 5) },  /* Eastern Standard */
350     { "edt",    tDAYZONE,  HOUR( 5) },  /* Eastern Daylight */
351     { "cst",    tZONE,     HOUR( 6) },  /* Central Standard */
352     { "cdt",    tDAYZONE,  HOUR( 6) },  /* Central Daylight */
353     { "mst",    tZONE,     HOUR( 7) },  /* Mountain Standard */
354     { "mdt",    tDAYZONE,  HOUR( 7) },  /* Mountain Daylight */
355     { "pst",    tZONE,     HOUR( 8) },  /* Pacific Standard */
356     { "pdt",    tDAYZONE,  HOUR( 8) },  /* Pacific Daylight */
357     { "yst",    tZONE,     HOUR( 9) },  /* Yukon Standard */
358     { "ydt",    tDAYZONE,  HOUR( 9) },  /* Yukon Daylight */
359     { "akst",   tZONE,     HOUR( 9) },  /* Alaska Standard */
360     { "akdt",   tDAYZONE,  HOUR( 9) },  /* Alaska Daylight */
361     { "hst",    tZONE,     HOUR(10) },  /* Hawaii Standard */
362     { "hast",   tZONE,     HOUR(10) },  /* Hawaii-Aleutian Standard */
363     { "hadt",   tDAYZONE,  HOUR(10) },  /* Hawaii-Aleutian Daylight */
364     { "ces",    tDAYZONE,  -HOUR(1) },  /* Central European Summer */
365     { "cest",   tDAYZONE,  -HOUR(1) },  /* Central European Summer */
366     { "mez",    tZONE,     -HOUR(1) },  /* Middle European */
367     { "mezt",   tDAYZONE,  -HOUR(1) },  /* Middle European Summer */
368     { "cet",    tZONE,     -HOUR(1) },  /* Central European */
369     { "met",    tZONE,     -HOUR(1) },  /* Middle European */
370     { "eet",    tZONE,     -HOUR(2) },  /* Eastern Europe */
371     { "msk",    tZONE,     -HOUR(3) },  /* Moscow Winter */
372     { "msd",    tDAYZONE,  -HOUR(3) },  /* Moscow Summer */
373     { "wast",   tZONE,     -HOUR(8) },  /* West Australian Standard */
374     { "wadt",   tDAYZONE,  -HOUR(8) },  /* West Australian Daylight */
375     { "hkt",    tZONE,     -HOUR(8) },  /* Hong Kong */
376     { "cct",    tZONE,     -HOUR(8) },  /* China Coast */
377     { "jst",    tZONE,     -HOUR(9) },  /* Japan Standard */
378     { "kst",    tZONE,     -HOUR(9) },  /* Korean Standard */
379     { "kdt",    tZONE,     -HOUR(9) },  /* Korean Daylight */
380     { "cast",   tZONE,     -(HOUR(9)+30) }, /* Central Australian Standard */
381     { "cadt",   tDAYZONE,  -(HOUR(9)+30) }, /* Central Australian Daylight */
382     { "east",   tZONE,     -HOUR(10) }, /* Eastern Australian Standard */
383     { "eadt",   tDAYZONE,  -HOUR(10) }, /* Eastern Australian Daylight */
384     { "nzst",   tZONE,     -HOUR(12) }, /* New Zealand Standard */
385     { "nzdt",   tDAYZONE,  -HOUR(12) }, /* New Zealand Daylight */
386
387     /* For completeness we include the following entries. */
388 #if 0
389
390     /* Duplicate names.  Either they conflict with a zone listed above
391      * (which is either more likely to be seen or just been in circulation
392      * longer), or they conflict with another zone in this section and
393      * we could not reasonably choose one over the other. */
394     { "fst",    tZONE,     HOUR( 2) },  /* Fernando De Noronha Standard */
395     { "fdt",    tDAYZONE,  HOUR( 2) },  /* Fernando De Noronha Daylight */
396     { "bst",    tZONE,     HOUR( 3) },  /* Brazil Standard */
397     { "est",    tZONE,     HOUR( 3) },  /* Eastern Standard (Brazil) */
398     { "edt",    tDAYZONE,  HOUR( 3) },  /* Eastern Daylight (Brazil) */
399     { "wst",    tZONE,     HOUR( 4) },  /* Western Standard (Brazil) */
400     { "wdt",    tDAYZONE,  HOUR( 4) },  /* Western Daylight (Brazil) */
401     { "cst",    tZONE,     HOUR( 5) },  /* Chile Standard */
402     { "cdt",    tDAYZONE,  HOUR( 5) },  /* Chile Daylight */
403     { "ast",    tZONE,     HOUR( 5) },  /* Acre Standard */
404     { "adt",    tDAYZONE,  HOUR( 5) },  /* Acre Daylight */
405     { "cst",    tZONE,     HOUR( 5) },  /* Cuba Standard */
406     { "cdt",    tDAYZONE,  HOUR( 5) },  /* Cuba Daylight */
407     { "est",    tZONE,     HOUR( 6) },  /* Easter Island Standard */
408     { "edt",    tDAYZONE,  HOUR( 6) },  /* Easter Island Daylight */
409     { "sst",    tZONE,     HOUR(11) },  /* Samoa Standard */
410     { "ist",    tZONE,     -HOUR(2) },  /* Israel Standard */
411     { "idt",    tDAYZONE,  -HOUR(2) },  /* Israel Daylight */
412     { "idt",    tDAYZONE,  -(HOUR(3)+30) }, /* Iran Daylight */
413     { "ist",    tZONE,     -(HOUR(3)+30) }, /* Iran Standard */
414     { "cst",     tZONE,     -HOUR(8) }, /* China Standard */
415     { "cdt",     tDAYZONE,  -HOUR(8) }, /* China Daylight */
416     { "sst",     tZONE,     -HOUR(8) }, /* Singapore Standard */
417
418     /* Dubious (e.g., not in Olson's TIMEZONE package) or obsolete. */
419     { "gst",    tZONE,     HOUR( 3) },  /* Greenland Standard */
420     { "wat",    tZONE,     -HOUR(1) },  /* West Africa */
421     { "at",     tZONE,     HOUR( 2) },  /* Azores */
422     { "gst",    tZONE,     -HOUR(10) }, /* Guam Standard */
423     { "nft",    tZONE,     HOUR(3)+30 }, /* Newfoundland */
424     { "idlw",   tZONE,     HOUR(12) },  /* International Date Line West */
425     { "mewt",   tZONE,     -HOUR(1) },  /* Middle European Winter */
426     { "mest",   tDAYZONE,  -HOUR(1) },  /* Middle European Summer */
427     { "swt",    tZONE,     -HOUR(1) },  /* Swedish Winter */
428     { "sst",    tDAYZONE,  -HOUR(1) },  /* Swedish Summer */
429     { "fwt",    tZONE,     -HOUR(1) },  /* French Winter */
430     { "fst",    tDAYZONE,  -HOUR(1) },  /* French Summer */
431     { "bt",     tZONE,     -HOUR(3) },  /* Baghdad */
432     { "it",     tZONE,     -(HOUR(3)+30) }, /* Iran */
433     { "zp4",    tZONE,     -HOUR(4) },  /* USSR Zone 3 */
434     { "zp5",    tZONE,     -HOUR(5) },  /* USSR Zone 4 */
435     { "ist",    tZONE,     -(HOUR(5)+30) }, /* Indian Standard */
436     { "zp6",    tZONE,     -HOUR(6) },  /* USSR Zone 5 */
437     { "nst",    tZONE,     -HOUR(7) },  /* North Sumatra */
438     { "sst",    tZONE,     -HOUR(7) },  /* South Sumatra */
439     { "jt",     tZONE,     -(HOUR(7)+30) }, /* Java (3pm in Cronusland!) */
440     { "nzt",    tZONE,     -HOUR(12) }, /* New Zealand */
441     { "idle",   tZONE,     -HOUR(12) }, /* International Date Line East */
442     { "cat",    tZONE,     HOUR(10) },  /* -- expired 1967 */
443     { "nt",     tZONE,     HOUR(11) },  /* -- expired 1967 */
444     { "ahst",   tZONE,     HOUR(10) },  /* -- expired 1983 */
445     { "hdt",    tDAYZONE,  HOUR(10) },  /* -- expired 1986 */
446 #endif /* 0 */
447 };
448
449
450 /* ARGSUSED */
451 static void
452 date_error(char *s)
453 {
454     /* NOTREACHED */
455 }
456
457
458 static time_t
459 ToSeconds(time_t Hours, time_t Minutes, time_t Seconds, MERIDIAN Meridian)
460 {
461     if (Minutes < 0 || Minutes > 59 || Seconds < 0 || Seconds > 61)
462         return -1;
463     if (Meridian == MER24) {
464         if (Hours < 0 || Hours > 23)
465             return -1;
466     }
467     else {
468         if (Hours < 1 || Hours > 12)
469             return -1;
470         if (Hours == 12)
471             Hours = 0;
472         if (Meridian == MERpm)
473             Hours += 12;
474     }
475     return (Hours * 60L + Minutes) * 60L + Seconds;
476 }
477
478
479 static time_t
480 Convert(time_t Month, time_t Day, time_t Year,
481         time_t Hours, time_t Minutes, time_t Seconds,
482         MERIDIAN Meridian, DSTMODE dst)
483 {
484     static int  DaysNormal[13] = {
485         0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
486     };
487     static int  DaysLeap[13] = {
488         0, 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
489     };
490     static int  LeapYears[] = {
491         1972, 1976, 1980, 1984, 1988, 1992, 1996,
492         2000, 2004, 2008, 2012, 2016, 2020, 2024, 2028, 2032, 2036
493     };
494     register int        *yp;
495     register int        *mp;
496     register time_t     Julian;
497     register int        i;
498     time_t              tod;
499
500     if (Year < 0)
501         Year = -Year;
502     if (Year < 100)
503         Year += 1900;
504     if (Year < EPOCH)
505         Year += 100;
506     for (mp = DaysNormal, yp = LeapYears; yp < ENDOF(LeapYears); yp++)
507         if (Year == *yp) {
508             mp = DaysLeap;
509             break;
510         }
511     if (Year < EPOCH || Year > END_OF_TIME
512      || Month < 1 || Month > 12
513      /* NOSTRICT *//* conversion from long may lose accuracy */
514      || Day < 1 || Day > mp[(int)Month])
515         return -1;
516
517     Julian = Day - 1 + (Year - EPOCH) * 365;
518     for (yp = LeapYears; yp < ENDOF(LeapYears); yp++, Julian++)
519         if (Year <= *yp)
520             break;
521     for (i = 1; i < Month; i++)
522         Julian += *++mp;
523     Julian *= SECSPERDAY;
524     Julian += yyTimezone * 60L;
525     if ((tod = ToSeconds(Hours, Minutes, Seconds, Meridian)) < 0)
526         return -1;
527     Julian += tod;
528     tod = Julian;
529     if (dst == DSTon || (dst == DSTmaybe && localtime(&tod)->tm_isdst))
530         Julian -= DST_OFFSET * 60L * 60L;
531     return Julian;
532 }
533
534
535 static time_t
536 DSTcorrect(time_t Start, time_t Future)
537 {
538     time_t      StartDay;
539     time_t      FutureDay;
540
541     StartDay = (localtime(&Start)->tm_hour + 1) % 24;
542     FutureDay = (localtime(&Future)->tm_hour + 1) % 24;
543     return (Future - Start) + (StartDay - FutureDay) * DST_OFFSET * 60L * 60L;
544 }
545
546
547 static time_t
548 RelativeMonth(time_t Start, time_t RelMonth)
549 {
550     struct tm   *tm;
551     time_t      Month;
552     time_t      Year;
553
554     tm = localtime(&Start);
555     Month = 12 * tm->tm_year + tm->tm_mon + RelMonth;
556     Year = Month / 12;
557     Month = Month % 12 + 1;
558     return DSTcorrect(Start,
559             Convert(Month, (time_t)tm->tm_mday, Year,
560                 (time_t)tm->tm_hour, (time_t)tm->tm_min, (time_t)tm->tm_sec,
561                 MER24, DSTmaybe));
562 }
563
564
565 static int
566 LookupWord(char *buff, register int length)
567 {
568     register char       *p;
569     register char       *q;
570     register TABLE      *tp;
571     register int        c;
572
573     p = buff;
574     c = p[0];
575
576     /* See if we have an abbreviation for a month. */
577     if (length == 3 || (length == 4 && p[3] == '.'))
578         for (tp = MonthDayTable; tp < ENDOF(MonthDayTable); tp++) {
579             q = tp->name;
580             if (c == q[0] && p[1] == q[1] && p[2] == q[2]) {
581                 yylval.Number = tp->value;
582                 return tp->type;
583             }
584         }
585     else
586         for (tp = MonthDayTable; tp < ENDOF(MonthDayTable); tp++)
587             if (c == tp->name[0] && strcmp(p, tp->name) == 0) {
588                 yylval.Number = tp->value;
589                 return tp->type;
590             }
591
592     /* Try for a timezone. */
593     for (tp = TimezoneTable; tp < ENDOF(TimezoneTable); tp++)
594         if (c == tp->name[0] && p[1] == tp->name[1]
595          && strcmp(p, tp->name) == 0) {
596             yylval.Number = tp->value;
597             return tp->type;
598         }
599
600     /* Try the units table. */
601     for (tp = UnitsTable; tp < ENDOF(UnitsTable); tp++)
602         if (c == tp->name[0] && strcmp(p, tp->name) == 0) {
603             yylval.Number = tp->value;
604             return tp->type;
605         }
606
607     /* Strip off any plural and try the units table again. */
608     if (--length > 0 && p[length] == 's') {
609         p[length] = '\0';
610         for (tp = UnitsTable; tp < ENDOF(UnitsTable); tp++)
611             if (c == tp->name[0] && strcmp(p, tp->name) == 0) {
612                 p[length] = 's';
613                 yylval.Number = tp->value;
614                 return tp->type;
615             }
616         p[length] = 's';
617     }
618     length++;
619
620     /* Drop out any periods. */
621     for (p = buff, q = (char*)buff; *q; q++)
622         if (*q != '.')
623             *p++ = *q;
624     *p = '\0';
625
626     /* Try the meridians. */
627     if (buff[1] == 'm' && buff[2] == '\0') {
628         if (buff[0] == 'a') {
629             yylval.Meridian = MERam;
630             return tMERIDIAN;
631         }
632         if (buff[0] == 'p') {
633             yylval.Meridian = MERpm;
634             return tMERIDIAN;
635         }
636     }
637
638     /* If we saw any periods, try the timezones again. */
639     if (p - buff != length) {
640         c = buff[0];
641         for (p = buff, tp = TimezoneTable; tp < ENDOF(TimezoneTable); tp++)
642             if (c == tp->name[0] && p[1] == tp->name[1]
643             && strcmp(p, tp->name) == 0) {
644                 yylval.Number = tp->value;
645                 return tp->type;
646             }
647     }
648
649     /* Unknown word -- assume GMT timezone. */
650     yylval.Number = 0;
651     return tZONE;
652 }
653
654
655 int
656 date_lex(void)
657 {
658     register char       c;
659     register char       *p;
660     char                buff[20];
661     register int        sign;
662     register int        i;
663     register int        nesting;
664
665     for ( ; ; ) {
666         /* Get first character after the whitespace. */
667         for ( ; ; ) {
668             while (isspace(*yyInput))
669                 yyInput++;
670             c = *yyInput;
671
672             /* Ignore RFC 822 comments, typically time zone names. */
673             if (c != LPAREN)
674                 break;
675             for (nesting = 1; (c = *++yyInput) != RPAREN || --nesting; )
676                 if (c == LPAREN)
677                     nesting++;
678                 else if (!IS7BIT(c) || c == '\0' || c == '\r'
679                      || (c == '\\' && ((c = *++yyInput) == '\0' || !IS7BIT(c))))
680                     /* Lexical error: bad comment. */
681                     return '?';
682             yyInput++;
683         }
684
685         /* A number? */
686         if (isdigit(c) || c == '-' || c == '+') {
687             if (c == '-' || c == '+') {
688                 sign = c == '-' ? -1 : 1;
689                 yyInput++;
690                 if (!isdigit(*yyInput))
691                     /* Skip the plus or minus sign. */
692                     continue;
693             }
694             else
695                 sign = 0;
696             for (i = 0; (c = *yyInput++) != '\0' && isdigit(c); )
697                 i = 10 * i + c - '0';
698             yyInput--;
699             yylval.Number = sign < 0 ? -i : i;
700             return sign ? tSNUMBER : tUNUMBER;
701         }
702
703         /* A word? */
704         if (isalpha(c)) {
705             for (p = buff; (c = *yyInput++) == '.' || isalpha(c); )
706                 if (p < &buff[sizeof buff - 1])
707                     *p++ = isupper(c) ? tolower(c) : c;
708             *p = '\0';
709             yyInput--;
710             return LookupWord(buff, p - buff);
711         }
712
713         return *yyInput++;
714     }
715 }
716
717
718 time_t
719 parsedate(char *p)
720 {
721     extern int          date_parse(void);
722     time_t              Start;
723
724     yyInput = p;
725
726     yyYear = 0;
727     yyMonth = 0;
728     yyDay = 0;
729     yyTimezone = 0;
730     yyDSTmode = DSTmaybe;
731     yyHour = 0;
732     yyMinutes = 0;
733     yySeconds = 0;
734     yyMeridian = MER24;
735     yyRelSeconds = 0;
736     yyRelMonth = 0;
737     yyHaveDate = 0;
738     yyHaveRel = 0;
739     yyHaveTime = 0;
740
741     if (date_parse() || yyHaveTime > 1 || yyHaveDate > 1)
742         return -1;
743
744     if (yyHaveDate || yyHaveTime) {
745         Start = Convert(yyMonth, yyDay, yyYear, yyHour, yyMinutes, yySeconds,
746                     yyMeridian, yyDSTmode);
747         if (Start < 0)
748             return -1;
749     }
750     else
751         return -1;
752
753     Start += yyRelSeconds;
754     if (yyRelMonth)
755         Start += RelativeMonth(Start, yyRelMonth);
756
757     /* Have to do *something* with a legitimate -1 so it's distinguishable
758      * from the error return value.  (Alternately could set errno on error.) */
759     return Start == -1 ? 0 : Start;
760 }
761
762
763 #ifdef TEST
764
765 #if YYDEBUG
766 extern int      yydebug;
767 #endif /* YYDEBUG */
768
769 /* ARGSUSED */
770 int
771 main(int ac, char *av[])
772 {
773     char        buff[128];
774     time_t      d;
775
776 #if YYDEBUG
777     yydebug = 1;
778 #endif /* YYDEBUG */
779
780     (void)printf("Enter date, or blank line to exit.\n\t> ");
781     for ( ; ; ) {
782         (void)printf("\t> ");
783         (void)fflush(stdout);
784         if (gets(buff) == NULL || buff[0] == '\n')
785             break;
786 #if YYDEBUG
787         if (strcmp(buff, "yydebug") == 0) {
788             yydebug = !yydebug;
789             printf("yydebug = %s\n", yydebug ? "on" : "off");
790             continue;
791         }
792 #endif /* YYDEBUG */
793         d = parsedate(buff, (TIMEINFO *)NULL);
794         if (d == -1)
795             (void)printf("Bad format - couldn't convert.\n");
796         else
797             (void)printf("%s", ctime(&d));
798     }
799
800     exit(0);
801     /* NOTREACHED */
802 }
803 #endif /* TEST */
804 #line 805 "y.tab.c"
805 #define YYABORT goto yyabort
806 #define YYREJECT goto yyabort
807 #define YYACCEPT goto yyaccept
808 #define YYERROR goto yyerrlab
809 int
810 yyparse()
811 {
812     register int yym, yyn, yystate;
813 #if YYDEBUG
814     register char *yys;
815     extern char *getenv();
816
817     if (yys = getenv("YYDEBUG"))
818     {
819         yyn = *yys;
820         if (yyn >= '0' && yyn <= '9')
821             yydebug = yyn - '0';
822     }
823 #endif
824
825     yynerrs = 0;
826     yyerrflag = 0;
827     yychar = (-1);
828
829     yyssp = yyss;
830     yyvsp = yyvs;
831     *yyssp = yystate = 0;
832
833 yyloop:
834     if (yyn = yydefred[yystate]) goto yyreduce;
835     if (yychar < 0)
836     {
837         if ((yychar = yylex()) < 0) yychar = 0;
838 #if YYDEBUG
839         if (yydebug)
840         {
841             yys = 0;
842             if (yychar <= YYMAXTOKEN) yys = yyname[yychar];
843             if (!yys) yys = "illegal-symbol";
844             printf("%sdebug: state %d, reading %d (%s)\n",
845                     YYPREFIX, yystate, yychar, yys);
846         }
847 #endif
848     }
849     if ((yyn = yysindex[yystate]) && (yyn += yychar) >= 0 &&
850             yyn <= YYTABLESIZE && yycheck[yyn] == yychar)
851     {
852 #if YYDEBUG
853         if (yydebug)
854             printf("%sdebug: state %d, shifting to state %d\n",
855                     YYPREFIX, yystate, yytable[yyn]);
856 #endif
857         if (yyssp >= yyss + yystacksize - 1)
858         {
859             goto yyoverflow;
860         }
861         *++yyssp = yystate = yytable[yyn];
862         *++yyvsp = yylval;
863         yychar = (-1);
864         if (yyerrflag > 0)  --yyerrflag;
865         goto yyloop;
866     }
867     if ((yyn = yyrindex[yystate]) && (yyn += yychar) >= 0 &&
868             yyn <= YYTABLESIZE && yycheck[yyn] == yychar)
869     {
870         yyn = yytable[yyn];
871         goto yyreduce;
872     }
873     if (yyerrflag) goto yyinrecovery;
874 #ifdef lint
875     goto yynewerror;
876 #endif
877 yynewerror:
878     yyerror("syntax error");
879 #ifdef lint
880     goto yyerrlab;
881 #endif
882 yyerrlab:
883     ++yynerrs;
884 yyinrecovery:
885     if (yyerrflag < 3)
886     {
887         yyerrflag = 3;
888         for (;;)
889         {
890             if ((yyn = yysindex[*yyssp]) && (yyn += YYERRCODE) >= 0 &&
891                     yyn <= YYTABLESIZE && yycheck[yyn] == YYERRCODE)
892             {
893 #if YYDEBUG
894                 if (yydebug)
895                     printf("%sdebug: state %d, error recovery shifting\
896  to state %d\n", YYPREFIX, *yyssp, yytable[yyn]);
897 #endif
898                 if (yyssp >= yyss + yystacksize - 1)
899                 {
900                     goto yyoverflow;
901                 }
902                 *++yyssp = yystate = yytable[yyn];
903                 *++yyvsp = yylval;
904                 goto yyloop;
905             }
906             else
907             {
908 #if YYDEBUG
909                 if (yydebug)
910                     printf("%sdebug: error recovery discarding state %d\n",
911                             YYPREFIX, *yyssp);
912 #endif
913                 if (yyssp <= yyss) goto yyabort;
914                 --yyssp;
915                 --yyvsp;
916             }
917         }
918     }
919     else
920     {
921         if (yychar == 0) goto yyabort;
922 #if YYDEBUG
923         if (yydebug)
924         {
925             yys = 0;
926             if (yychar <= YYMAXTOKEN) yys = yyname[yychar];
927             if (!yys) yys = "illegal-symbol";
928             printf("%sdebug: state %d, error recovery discards token %d (%s)\n",
929                     YYPREFIX, yystate, yychar, yys);
930         }
931 #endif
932         yychar = (-1);
933         goto yyloop;
934     }
935 yyreduce:
936 #if YYDEBUG
937     if (yydebug)
938         printf("%sdebug: state %d, reducing by rule %d (%s)\n",
939                 YYPREFIX, yystate, yyn, yyrule[yyn]);
940 #endif
941     yym = yylen[yyn];
942     yyval = yyvsp[1-yym];
943     switch (yyn)
944     {
945 case 3:
946 #line 118 "parsedate.y"
947 {
948             yyHaveTime++;
949 #ifdef lint
950             /* I am compulsive about lint natterings... */
951             if (yyHaveTime == -1) {
952                 YYERROR;
953             }
954 #endif /* lint */
955         }
956 break;
957 case 4:
958 #line 127 "parsedate.y"
959 {
960             yyHaveTime++;
961             yyTimezone = yyvsp[0].Number;
962         }
963 break;
964 case 5:
965 #line 131 "parsedate.y"
966 {
967             yyHaveDate++;
968         }
969 break;
970 case 6:
971 #line 134 "parsedate.y"
972 {
973             yyHaveRel = 1;
974         }
975 break;
976 case 7:
977 #line 139 "parsedate.y"
978 {
979             if (yyvsp[-1].Number < 100) {
980                 yyHour = yyvsp[-1].Number;
981                 yyMinutes = 0;
982             }
983             else {
984                 yyHour = yyvsp[-1].Number / 100;
985                 yyMinutes = yyvsp[-1].Number % 100;
986             }
987             yySeconds = 0;
988             yyMeridian = yyvsp[0].Meridian;
989         }
990 break;
991 case 8:
992 #line 151 "parsedate.y"
993 {
994             yyHour = yyvsp[-3].Number;
995             yyMinutes = yyvsp[-1].Number;
996             yySeconds = 0;
997             yyMeridian = yyvsp[0].Meridian;
998         }
999 break;
1000 case 9:
1001 #line 157 "parsedate.y"
1002 {
1003             yyHour = yyvsp[-3].Number;
1004             yyMinutes = yyvsp[-1].Number;
1005             yyTimezone = yyvsp[0].Number;
1006             yyMeridian = MER24;
1007             yyDSTmode = DSToff;
1008         }
1009 break;
1010 case 10:
1011 #line 164 "parsedate.y"
1012 {
1013             yyHour = yyvsp[-5].Number;
1014             yyMinutes = yyvsp[-3].Number;
1015             yySeconds = yyvsp[-1].Number;
1016             yyMeridian = yyvsp[0].Meridian;
1017         }
1018 break;
1019 case 11:
1020 #line 170 "parsedate.y"
1021 {
1022             yyHour = yyvsp[-5].Number;
1023             yyMinutes = yyvsp[-3].Number;
1024             yySeconds = yyvsp[-1].Number;
1025             yyTimezone = yyvsp[0].Number;
1026             yyMeridian = MER24;
1027             yyDSTmode = DSToff;
1028         }
1029 break;
1030 case 12:
1031 #line 180 "parsedate.y"
1032 {
1033             yyval.Number = yyvsp[0].Number;
1034             yyDSTmode = DSToff;
1035         }
1036 break;
1037 case 13:
1038 #line 184 "parsedate.y"
1039 {
1040             yyval.Number = yyvsp[0].Number;
1041             yyDSTmode = DSTon;
1042         }
1043 break;
1044 case 14:
1045 #line 188 "parsedate.y"
1046 {
1047             /* Only allow "GMT+300" and "GMT-0800" */
1048             if (yyvsp[-1].Number != 0) {
1049                 YYABORT;
1050             }
1051             yyval.Number = yyvsp[0].Number;
1052             yyDSTmode = DSToff;
1053         }
1054 break;
1055 case 15:
1056 #line 196 "parsedate.y"
1057 {
1058             yyval.Number = yyvsp[0].Number;
1059             yyDSTmode = DSToff;
1060         }
1061 break;
1062 case 16:
1063 #line 202 "parsedate.y"
1064 {
1065             int         i;
1066
1067             /* Unix and GMT and numeric timezones -- a little confusing. */
1068             if (yyvsp[0].Number < 0) {
1069                 /* Don't work with negative modulus. */
1070                 yyvsp[0].Number = -yyvsp[0].Number;
1071                 if (yyvsp[0].Number > 9999 || (i = yyvsp[0].Number % 100) >= 60) {
1072                     YYABORT;
1073                 }
1074                 yyval.Number = (yyvsp[0].Number / 100) * 60 + i;
1075             }
1076             else {
1077                 if (yyvsp[0].Number > 9999 || (i = yyvsp[0].Number % 100) >= 60) {
1078                     YYABORT;
1079                 }
1080                 yyval.Number = -((yyvsp[0].Number / 100) * 60 + i);
1081             }
1082         }
1083 break;
1084 case 17:
1085 #line 223 "parsedate.y"
1086 {
1087             yyMonth = yyvsp[-2].Number;
1088             yyDay = yyvsp[0].Number;
1089         }
1090 break;
1091 case 18:
1092 #line 227 "parsedate.y"
1093 {
1094             if (yyvsp[-4].Number > 100) {
1095                 yyYear = yyvsp[-4].Number;
1096                 yyMonth = yyvsp[-2].Number;
1097                 yyDay = yyvsp[0].Number;
1098             }
1099             else {
1100                 yyMonth = yyvsp[-4].Number;
1101                 yyDay = yyvsp[-2].Number;
1102                 yyYear = yyvsp[0].Number;
1103             }
1104         }
1105 break;
1106 case 19:
1107 #line 239 "parsedate.y"
1108 {
1109             yyMonth = yyvsp[-1].Number;
1110             yyDay = yyvsp[0].Number;
1111         }
1112 break;
1113 case 20:
1114 #line 243 "parsedate.y"
1115 {
1116             yyMonth = yyvsp[-3].Number;
1117             yyDay = yyvsp[-2].Number;
1118             yyYear = yyvsp[0].Number;
1119         }
1120 break;
1121 case 21:
1122 #line 248 "parsedate.y"
1123 {
1124             yyDay = yyvsp[-1].Number;
1125             yyMonth = yyvsp[0].Number;
1126         }
1127 break;
1128 case 22:
1129 #line 252 "parsedate.y"
1130 {
1131             yyDay = yyvsp[-2].Number;
1132             yyMonth = yyvsp[-1].Number;
1133             yyYear = yyvsp[0].Number;
1134         }
1135 break;
1136 case 23:
1137 #line 257 "parsedate.y"
1138 {
1139             yyDay = yyvsp[-2].Number;
1140             yyMonth = yyvsp[-1].Number;
1141             yyYear = yyvsp[0].Number;
1142         }
1143 break;
1144 case 24:
1145 #line 264 "parsedate.y"
1146 {
1147             yyRelSeconds += yyvsp[-1].Number * yyvsp[0].Number;
1148         }
1149 break;
1150 case 25:
1151 #line 267 "parsedate.y"
1152 {
1153             yyRelSeconds += yyvsp[-1].Number * yyvsp[0].Number;
1154         }
1155 break;
1156 case 26:
1157 #line 270 "parsedate.y"
1158 {
1159             yyRelMonth += yyvsp[-1].Number * yyvsp[0].Number;
1160         }
1161 break;
1162 case 27:
1163 #line 273 "parsedate.y"
1164 {
1165             yyRelMonth += yyvsp[-1].Number * yyvsp[0].Number;
1166         }
1167 break;
1168 case 28:
1169 #line 278 "parsedate.y"
1170 {
1171             yyval.Meridian = MER24;
1172         }
1173 break;
1174 case 29:
1175 #line 281 "parsedate.y"
1176 {
1177             yyval.Meridian = yyvsp[0].Meridian;
1178         }
1179 break;
1180 #line 1181 "y.tab.c"
1181     }
1182     yyssp -= yym;
1183     yystate = *yyssp;
1184     yyvsp -= yym;
1185     yym = yylhs[yyn];
1186     if (yystate == 0 && yym == 0)
1187     {
1188 #if YYDEBUG
1189         if (yydebug)
1190             printf("%sdebug: after reduction, shifting from state 0 to\
1191  state %d\n", YYPREFIX, YYFINAL);
1192 #endif
1193         yystate = YYFINAL;
1194         *++yyssp = YYFINAL;
1195         *++yyvsp = yyval;
1196         if (yychar < 0)
1197         {
1198             if ((yychar = yylex()) < 0) yychar = 0;
1199 #if YYDEBUG
1200             if (yydebug)
1201             {
1202                 yys = 0;
1203                 if (yychar <= YYMAXTOKEN) yys = yyname[yychar];
1204                 if (!yys) yys = "illegal-symbol";
1205                 printf("%sdebug: state %d, reading %d (%s)\n",
1206                         YYPREFIX, YYFINAL, yychar, yys);
1207             }
1208 #endif
1209         }
1210         if (yychar == 0) goto yyaccept;
1211         goto yyloop;
1212     }
1213     if ((yyn = yygindex[yym]) && (yyn += yystate) >= 0 &&
1214             yyn <= YYTABLESIZE && yycheck[yyn] == yystate)
1215         yystate = yytable[yyn];
1216     else
1217         yystate = yydgoto[yym];
1218 #if YYDEBUG
1219     if (yydebug)
1220         printf("%sdebug: after reduction, shifting from state %d \
1221 to state %d\n", YYPREFIX, *yyssp, yystate);
1222 #endif
1223     if (yyssp >= yyss + yystacksize - 1)
1224     {
1225         goto yyoverflow;
1226     }
1227     *++yyssp = yystate;
1228     *++yyvsp = yyval;
1229     goto yyloop;
1230 yyoverflow:
1231     yyerror("yacc stack overflow");
1232 yyabort:
1233     return (1);
1234 yyaccept:
1235     return (0);
1236 }