5 ** Originally written by Steven M. Bellovin <smb@research.att.com> while
6 ** at the University of North Carolina at Chapel Hill. Later tweaked by
7 ** a couple of people on Usenet. Completely overhauled by Rich $alz
8 ** <rsalz@osf.org> and Jim Berets <jberets@bbn.com> in August, 1990.
9 ** Further revised (removed obsolete constructs and cleaned up timezone
10 ** names) in August, 1991, by Rich. Paul Eggert <eggert@twinsun.com>
11 ** helped in September, 1992. Art Cancro <ajc@uncnsrd.mt-kisco.ny.us> cleaned
12 ** it up for ANSI C in December, 1999.
14 ** This grammar has six shift/reduce conflicts.
16 ** This code is in the public domain and has no copyright.
18 /* SUPPRESS 530 *//* Empty body for statement */
19 /* SUPPRESS 593 on yyerrlab *//* Label was not used */
20 /* SUPPRESS 593 on yynewstate *//* Label was not used */
21 /* SUPPRESS 595 on yypvt *//* Automatic variable may be used before set */
23 #include <sys/types.h>
26 #include "parsedate.h"
30 #define yyparse date_parse
31 #define yylex date_lex
32 #define yyerror date_error
35 /* See the LeapYears table in Convert. */
37 #define END_OF_TIME 2038
38 /* Constants for general time calculations. */
40 #define SECSPERDAY (24L * 60L * 60L)
41 /* Readability for TABLE stuff. */
42 #define HOUR(x) (x * 60)
46 #define IS7BIT(x) ((unsigned int)(x) < 0200)
48 #define SIZEOF(array) ((int)(sizeof array / sizeof array[0]))
49 #define ENDOF(array) (&array[SIZEOF(array)])
53 ** An entry in the lexical lookup table.
55 typedef struct _TABLE {
62 ** Daylight-savings mode: on, off, or not yet known.
64 typedef enum _DSTMODE {
65 DSTon, DSToff, DSTmaybe
69 ** Meridian: am, pm, or 24-hour style.
71 typedef enum _MERIDIAN {
77 ** Global variables. We could get rid of most of them by using a yacc
78 ** union, but this is more efficient. (This routine predates the
79 ** yacc %union construct.)
82 static DSTMODE yyDSTmode;
83 static int yyHaveDate;
85 static int yyHaveTime;
86 static time_t yyTimezone;
89 static time_t yyMinutes;
90 static time_t yyMonth;
91 static time_t yySeconds;
93 static MERIDIAN yyMeridian;
94 static time_t yyRelMonth;
95 static time_t yyRelSeconds;
98 static void date_error(char *);
100 # line 100 "parsedate.y"
107 enum _MERIDIAN Meridian;
110 # define tDAYZONE 258
111 # define tMERIDIAN 259
113 # define tMONTH_UNIT 261
114 # define tSEC_UNIT 262
115 # define tSNUMBER 263
116 # define tUNUMBER 264
119 #include <inttypes.h>
131 #if defined(__cplusplus) || defined(__STDC__)
133 #if defined(__cplusplus) && defined(__EXTERN_C__)
137 #if defined(__cplusplus)
138 void yyerror(const char *);
145 #if defined(__cplusplus) && defined(__EXTERN_C__)
151 #define yyclearin yychar = -1
152 #define yyerrok yyerrflag = 0
154 extern int yyerrflag;
157 typedef int yytabelem;
159 #define YYMAXDEPTH 150
162 int yy_yys[YYMAXDEPTH], *yys = yy_yys;
163 YYSTYPE yy_yyv[YYMAXDEPTH], *yyv = yy_yyv;
164 #else /* user does initial allocation */
168 static int yymaxdepth = YYMAXDEPTH;
169 # define YYERRCODE 256
171 # line 286 "parsedate.y"
174 /* Month and day table. */
175 static TABLE MonthDayTable[] = {
176 { "january", tMONTH, 1 },
177 { "february", tMONTH, 2 },
178 { "march", tMONTH, 3 },
179 { "april", tMONTH, 4 },
180 { "may", tMONTH, 5 },
181 { "june", tMONTH, 6 },
182 { "july", tMONTH, 7 },
183 { "august", tMONTH, 8 },
184 { "september", tMONTH, 9 },
185 { "october", tMONTH, 10 },
186 { "november", tMONTH, 11 },
187 { "december", tMONTH, 12 },
188 /* The value of the day isn't used... */
189 { "sunday", tDAY, 0 },
190 { "monday", tDAY, 0 },
191 { "tuesday", tDAY, 0 },
192 { "wednesday", tDAY, 0 },
193 { "thursday", tDAY, 0 },
194 { "friday", tDAY, 0 },
195 { "saturday", tDAY, 0 },
198 /* Time units table. */
199 static TABLE UnitsTable[] = {
200 { "year", tMONTH_UNIT, 12 },
201 { "month", tMONTH_UNIT, 1 },
202 { "week", tSEC_UNIT, 7L * 24 * 60 * 60 },
203 { "day", tSEC_UNIT, 1L * 24 * 60 * 60 },
204 { "hour", tSEC_UNIT, 60 * 60 },
205 { "minute", tSEC_UNIT, 60 },
206 { "min", tSEC_UNIT, 60 },
207 { "second", tSEC_UNIT, 1 },
208 { "sec", tSEC_UNIT, 1 },
211 /* Timezone table. */
212 static TABLE TimezoneTable[] = {
213 { "gmt", tZONE, HOUR( 0) }, /* Greenwich Mean */
214 { "ut", tZONE, HOUR( 0) }, /* Universal */
215 { "utc", tZONE, HOUR( 0) }, /* Universal Coordinated */
216 { "cut", tZONE, HOUR( 0) }, /* Coordinated Universal */
217 { "z", tZONE, HOUR( 0) }, /* Greenwich Mean */
218 { "wet", tZONE, HOUR( 0) }, /* Western European */
219 { "bst", tDAYZONE, HOUR( 0) }, /* British Summer */
220 { "nst", tZONE, HOUR(3)+30 }, /* Newfoundland Standard */
221 { "ndt", tDAYZONE, HOUR(3)+30 }, /* Newfoundland Daylight */
222 { "ast", tZONE, HOUR( 4) }, /* Atlantic Standard */
223 { "adt", tDAYZONE, HOUR( 4) }, /* Atlantic Daylight */
224 { "est", tZONE, HOUR( 5) }, /* Eastern Standard */
225 { "edt", tDAYZONE, HOUR( 5) }, /* Eastern Daylight */
226 { "cst", tZONE, HOUR( 6) }, /* Central Standard */
227 { "cdt", tDAYZONE, HOUR( 6) }, /* Central Daylight */
228 { "mst", tZONE, HOUR( 7) }, /* Mountain Standard */
229 { "mdt", tDAYZONE, HOUR( 7) }, /* Mountain Daylight */
230 { "pst", tZONE, HOUR( 8) }, /* Pacific Standard */
231 { "pdt", tDAYZONE, HOUR( 8) }, /* Pacific Daylight */
232 { "yst", tZONE, HOUR( 9) }, /* Yukon Standard */
233 { "ydt", tDAYZONE, HOUR( 9) }, /* Yukon Daylight */
234 { "akst", tZONE, HOUR( 9) }, /* Alaska Standard */
235 { "akdt", tDAYZONE, HOUR( 9) }, /* Alaska Daylight */
236 { "hst", tZONE, HOUR(10) }, /* Hawaii Standard */
237 { "hast", tZONE, HOUR(10) }, /* Hawaii-Aleutian Standard */
238 { "hadt", tDAYZONE, HOUR(10) }, /* Hawaii-Aleutian Daylight */
239 { "ces", tDAYZONE, -HOUR(1) }, /* Central European Summer */
240 { "cest", tDAYZONE, -HOUR(1) }, /* Central European Summer */
241 { "mez", tZONE, -HOUR(1) }, /* Middle European */
242 { "mezt", tDAYZONE, -HOUR(1) }, /* Middle European Summer */
243 { "cet", tZONE, -HOUR(1) }, /* Central European */
244 { "met", tZONE, -HOUR(1) }, /* Middle European */
245 { "eet", tZONE, -HOUR(2) }, /* Eastern Europe */
246 { "msk", tZONE, -HOUR(3) }, /* Moscow Winter */
247 { "msd", tDAYZONE, -HOUR(3) }, /* Moscow Summer */
248 { "wast", tZONE, -HOUR(8) }, /* West Australian Standard */
249 { "wadt", tDAYZONE, -HOUR(8) }, /* West Australian Daylight */
250 { "hkt", tZONE, -HOUR(8) }, /* Hong Kong */
251 { "cct", tZONE, -HOUR(8) }, /* China Coast */
252 { "jst", tZONE, -HOUR(9) }, /* Japan Standard */
253 { "kst", tZONE, -HOUR(9) }, /* Korean Standard */
254 { "kdt", tZONE, -HOUR(9) }, /* Korean Daylight */
255 { "cast", tZONE, -(HOUR(9)+30) }, /* Central Australian Standard */
256 { "cadt", tDAYZONE, -(HOUR(9)+30) }, /* Central Australian Daylight */
257 { "east", tZONE, -HOUR(10) }, /* Eastern Australian Standard */
258 { "eadt", tDAYZONE, -HOUR(10) }, /* Eastern Australian Daylight */
259 { "nzst", tZONE, -HOUR(12) }, /* New Zealand Standard */
260 { "nzdt", tDAYZONE, -HOUR(12) }, /* New Zealand Daylight */
262 /* For completeness we include the following entries. */
265 /* Duplicate names. Either they conflict with a zone listed above
266 * (which is either more likely to be seen or just been in circulation
267 * longer), or they conflict with another zone in this section and
268 * we could not reasonably choose one over the other. */
269 { "fst", tZONE, HOUR( 2) }, /* Fernando De Noronha Standard */
270 { "fdt", tDAYZONE, HOUR( 2) }, /* Fernando De Noronha Daylight */
271 { "bst", tZONE, HOUR( 3) }, /* Brazil Standard */
272 { "est", tZONE, HOUR( 3) }, /* Eastern Standard (Brazil) */
273 { "edt", tDAYZONE, HOUR( 3) }, /* Eastern Daylight (Brazil) */
274 { "wst", tZONE, HOUR( 4) }, /* Western Standard (Brazil) */
275 { "wdt", tDAYZONE, HOUR( 4) }, /* Western Daylight (Brazil) */
276 { "cst", tZONE, HOUR( 5) }, /* Chile Standard */
277 { "cdt", tDAYZONE, HOUR( 5) }, /* Chile Daylight */
278 { "ast", tZONE, HOUR( 5) }, /* Acre Standard */
279 { "adt", tDAYZONE, HOUR( 5) }, /* Acre Daylight */
280 { "cst", tZONE, HOUR( 5) }, /* Cuba Standard */
281 { "cdt", tDAYZONE, HOUR( 5) }, /* Cuba Daylight */
282 { "est", tZONE, HOUR( 6) }, /* Easter Island Standard */
283 { "edt", tDAYZONE, HOUR( 6) }, /* Easter Island Daylight */
284 { "sst", tZONE, HOUR(11) }, /* Samoa Standard */
285 { "ist", tZONE, -HOUR(2) }, /* Israel Standard */
286 { "idt", tDAYZONE, -HOUR(2) }, /* Israel Daylight */
287 { "idt", tDAYZONE, -(HOUR(3)+30) }, /* Iran Daylight */
288 { "ist", tZONE, -(HOUR(3)+30) }, /* Iran Standard */
289 { "cst", tZONE, -HOUR(8) }, /* China Standard */
290 { "cdt", tDAYZONE, -HOUR(8) }, /* China Daylight */
291 { "sst", tZONE, -HOUR(8) }, /* Singapore Standard */
293 /* Dubious (e.g., not in Olson's TIMEZONE package) or obsolete. */
294 { "gst", tZONE, HOUR( 3) }, /* Greenland Standard */
295 { "wat", tZONE, -HOUR(1) }, /* West Africa */
296 { "at", tZONE, HOUR( 2) }, /* Azores */
297 { "gst", tZONE, -HOUR(10) }, /* Guam Standard */
298 { "nft", tZONE, HOUR(3)+30 }, /* Newfoundland */
299 { "idlw", tZONE, HOUR(12) }, /* International Date Line West */
300 { "mewt", tZONE, -HOUR(1) }, /* Middle European Winter */
301 { "mest", tDAYZONE, -HOUR(1) }, /* Middle European Summer */
302 { "swt", tZONE, -HOUR(1) }, /* Swedish Winter */
303 { "sst", tDAYZONE, -HOUR(1) }, /* Swedish Summer */
304 { "fwt", tZONE, -HOUR(1) }, /* French Winter */
305 { "fst", tDAYZONE, -HOUR(1) }, /* French Summer */
306 { "bt", tZONE, -HOUR(3) }, /* Baghdad */
307 { "it", tZONE, -(HOUR(3)+30) }, /* Iran */
308 { "zp4", tZONE, -HOUR(4) }, /* USSR Zone 3 */
309 { "zp5", tZONE, -HOUR(5) }, /* USSR Zone 4 */
310 { "ist", tZONE, -(HOUR(5)+30) }, /* Indian Standard */
311 { "zp6", tZONE, -HOUR(6) }, /* USSR Zone 5 */
312 { "nst", tZONE, -HOUR(7) }, /* North Sumatra */
313 { "sst", tZONE, -HOUR(7) }, /* South Sumatra */
314 { "jt", tZONE, -(HOUR(7)+30) }, /* Java (3pm in Cronusland!) */
315 { "nzt", tZONE, -HOUR(12) }, /* New Zealand */
316 { "idle", tZONE, -HOUR(12) }, /* International Date Line East */
317 { "cat", tZONE, HOUR(10) }, /* -- expired 1967 */
318 { "nt", tZONE, HOUR(11) }, /* -- expired 1967 */
319 { "ahst", tZONE, HOUR(10) }, /* -- expired 1983 */
320 { "hdt", tDAYZONE, HOUR(10) }, /* -- expired 1986 */
334 ToSeconds(time_t Hours, time_t Minutes, time_t Seconds, MERIDIAN Meridian)
336 if (Minutes < 0 || Minutes > 59 || Seconds < 0 || Seconds > 61)
338 if (Meridian == MER24) {
339 if (Hours < 0 || Hours > 23)
343 if (Hours < 1 || Hours > 12)
347 if (Meridian == MERpm)
350 return (Hours * 60L + Minutes) * 60L + Seconds;
355 Convert(time_t Month, time_t Day, time_t Year,
356 time_t Hours, time_t Minutes, time_t Seconds,
357 MERIDIAN Meridian, DSTMODE dst)
359 static int DaysNormal[13] = {
360 0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
362 static int DaysLeap[13] = {
363 0, 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
365 static int LeapYears[] = {
366 1972, 1976, 1980, 1984, 1988, 1992, 1996,
367 2000, 2004, 2008, 2012, 2016, 2020, 2024, 2028, 2032, 2036
371 register time_t Julian;
381 for (mp = DaysNormal, yp = LeapYears; yp < ENDOF(LeapYears); yp++)
386 if (Year < EPOCH || Year > END_OF_TIME
387 || Month < 1 || Month > 12
388 /* NOSTRICT *//* conversion from long may lose accuracy */
389 || Day < 1 || Day > mp[(int)Month])
392 Julian = Day - 1 + (Year - EPOCH) * 365;
393 for (yp = LeapYears; yp < ENDOF(LeapYears); yp++, Julian++)
396 for (i = 1; i < Month; i++)
398 Julian *= SECSPERDAY;
399 Julian += yyTimezone * 60L;
400 if ((tod = ToSeconds(Hours, Minutes, Seconds, Meridian)) < 0)
404 if (dst == DSTon || (dst == DSTmaybe && localtime(&tod)->tm_isdst))
405 Julian -= DST_OFFSET * 60L * 60L;
411 DSTcorrect(time_t Start, time_t Future)
416 StartDay = (localtime(&Start)->tm_hour + 1) % 24;
417 FutureDay = (localtime(&Future)->tm_hour + 1) % 24;
418 return (Future - Start) + (StartDay - FutureDay) * DST_OFFSET * 60L * 60L;
423 RelativeMonth(time_t Start, time_t RelMonth)
429 tm = localtime(&Start);
430 Month = 12 * tm->tm_year + tm->tm_mon + RelMonth;
432 Month = Month % 12 + 1;
433 return DSTcorrect(Start,
434 Convert(Month, (time_t)tm->tm_mday, Year,
435 (time_t)tm->tm_hour, (time_t)tm->tm_min, (time_t)tm->tm_sec,
441 LookupWord(char *buff, register int length)
451 /* See if we have an abbreviation for a month. */
452 if (length == 3 || (length == 4 && p[3] == '.'))
453 for (tp = MonthDayTable; tp < ENDOF(MonthDayTable); tp++) {
455 if (c == q[0] && p[1] == q[1] && p[2] == q[2]) {
456 yylval.Number = tp->value;
461 for (tp = MonthDayTable; tp < ENDOF(MonthDayTable); tp++)
462 if (c == tp->name[0] && strcmp(p, tp->name) == 0) {
463 yylval.Number = tp->value;
467 /* Try for a timezone. */
468 for (tp = TimezoneTable; tp < ENDOF(TimezoneTable); tp++)
469 if (c == tp->name[0] && p[1] == tp->name[1]
470 && strcmp(p, tp->name) == 0) {
471 yylval.Number = tp->value;
475 /* Try the units table. */
476 for (tp = UnitsTable; tp < ENDOF(UnitsTable); tp++)
477 if (c == tp->name[0] && strcmp(p, tp->name) == 0) {
478 yylval.Number = tp->value;
482 /* Strip off any plural and try the units table again. */
483 if (--length > 0 && p[length] == 's') {
485 for (tp = UnitsTable; tp < ENDOF(UnitsTable); tp++)
486 if (c == tp->name[0] && strcmp(p, tp->name) == 0) {
488 yylval.Number = tp->value;
495 /* Drop out any periods. */
496 for (p = buff, q = (char*)buff; *q; q++)
501 /* Try the meridians. */
502 if (buff[1] == 'm' && buff[2] == '\0') {
503 if (buff[0] == 'a') {
504 yylval.Meridian = MERam;
507 if (buff[0] == 'p') {
508 yylval.Meridian = MERpm;
513 /* If we saw any periods, try the timezones again. */
514 if (p - buff != length) {
516 for (p = buff, tp = TimezoneTable; tp < ENDOF(TimezoneTable); tp++)
517 if (c == tp->name[0] && p[1] == tp->name[1]
518 && strcmp(p, tp->name) == 0) {
519 yylval.Number = tp->value;
524 /* Unknown word -- assume GMT timezone. */
538 register int nesting;
541 /* Get first character after the whitespace. */
543 while (isspace(*yyInput))
547 /* Ignore RFC 822 comments, typically time zone names. */
550 for (nesting = 1; (c = *++yyInput) != RPAREN || --nesting; )
553 else if (!IS7BIT(c) || c == '\0' || c == '\r'
554 || (c == '\\' && ((c = *++yyInput) == '\0' || !IS7BIT(c))))
555 /* Lexical error: bad comment. */
561 if (isdigit(c) || c == '-' || c == '+') {
562 if (c == '-' || c == '+') {
563 sign = c == '-' ? -1 : 1;
565 if (!isdigit(*yyInput))
566 /* Skip the plus or minus sign. */
571 for (i = 0; (c = *yyInput++) != '\0' && isdigit(c); )
572 i = 10 * i + c - '0';
574 yylval.Number = sign < 0 ? -i : i;
575 return sign ? tSNUMBER : tUNUMBER;
580 for (p = buff; (c = *yyInput++) == '.' || isalpha(c); )
581 if (p < &buff[sizeof buff - 1])
582 *p++ = isupper(c) ? tolower(c) : c;
585 return LookupWord(buff, p - buff);
596 extern int date_parse(void);
605 yyDSTmode = DSTmaybe;
616 if (date_parse() || yyHaveTime > 1 || yyHaveDate > 1)
619 if (yyHaveDate || yyHaveTime) {
620 Start = Convert(yyMonth, yyDay, yyYear, yyHour, yyMinutes, yySeconds,
621 yyMeridian, yyDSTmode);
628 Start += yyRelSeconds;
630 Start += RelativeMonth(Start, yyRelMonth);
632 /* Have to do *something* with a legitimate -1 so it's distinguishable
633 * from the error return value. (Alternately could set errno on error.) */
634 return Start == -1 ? 0 : Start;
646 main(int ac, char *av[])
655 (void)printf("Enter date, or blank line to exit.\n\t> ");
657 (void)printf("\t> ");
658 (void)fflush(stdout);
659 if (gets(buff) == NULL || buff[0] == '\n')
662 if (strcmp(buff, "yydebug") == 0) {
664 printf("yydebug = %s\n", yydebug ? "on" : "off");
668 d = parsedate(buff, (TIMEINFO *)NULL);
670 (void)printf("Bad format - couldn't convert.\n");
672 (void)printf("%s", ctime(&d));
679 static const yytabelem yyexca[] ={
686 static const yytabelem yyact[]={
688 17, 12, 34, 40, 39, 21, 14, 8, 11, 14,
689 7, 16, 38, 9, 6, 36, 31, 29, 28, 27,
690 22, 14, 25, 24, 37, 35, 30, 23, 13, 15,
691 5, 4, 3, 2, 1, 10, 0, 0, 0, 0,
692 26, 0, 0, 0, 0, 0, 0, 0, 0, 0,
693 0, 0, 0, 0, 0, 0, 33, 32, 0, 0,
694 0, 0, 0, 0, 0, 0, 0, 42, 41, 0,
695 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
696 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
697 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
698 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
699 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
700 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
701 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
702 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
703 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
704 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
705 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
706 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
707 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
708 0, 0, 0, 21, 0, 0, 0, 14, 0, 0,
709 0, 0, 21, 18, 20, 19 };
710 static const yytabelem yypact[]={
712 -10000000, -250,-10000000, -257,-10000000,-10000000, -47, -244, -17, -239,
713 -10000000, -242,-10000000,-10000000,-10000000,-10000000, -245, -246, -247,-10000000,
714 -10000000,-10000000, -18, -248,-10000000,-10000000,-10000000, -56, -22,-10000000,
715 -249, -236,-10000000,-10000000, -252, -260,-10000000, -261, -254,-10000000,
716 -10000000,-10000000,-10000000 };
717 static const yytabelem yypgo[]={
719 0, 28, 35, 29, 34, 33, 32, 31, 30 };
720 static const yytabelem yyr1[]={
722 0, 4, 4, 5, 5, 5, 5, 6, 6, 6,
723 6, 6, 2, 2, 2, 2, 1, 7, 7, 7,
724 7, 7, 7, 7, 8, 8, 8, 8, 3, 3 };
725 static const yytabelem yyr2[]={
727 0, 0, 4, 3, 5, 3, 3, 5, 9, 9,
728 13, 13, 3, 3, 5, 3, 3, 7, 11, 5,
729 9, 5, 7, 11, 5, 5, 5, 5, 1, 3 };
730 static const yytabelem yychk[]={
732 -10000000, -4, -5, -6, -7, -8, 264, 260, 257, 263,
733 -2, 265, 258, -1, 263, -3, 58, 47, 260, 262,
734 261, 259, 264, 44, 262, 261, -1, 264, 264, 264,
735 44, 264, -3, -1, 58, 47, 264, 260, 264, 264,
737 static const yytabelem yydef[]={
739 1, -2, 2, 3, 5, 6, 28, 0, 0, 0,
740 4, 12, 13, 15, 16, 7, 0, 0, 21, 25,
741 27, 29, 19, 0, 24, 26, 14, 28, 17, 22,
742 0, 0, 8, 9, 0, 0, 20, 0, 28, 18,
748 { char *t_name; int t_val; } yytoktype;
750 # define YYDEBUG 0 /* don't allow debugging */
766 "-unknown-", -1 /* ends search */
771 "-no such reduction-",
772 "spec : /* empty */",
778 "time : tUNUMBER o_merid",
779 "time : tUNUMBER ':' tUNUMBER o_merid",
780 "time : tUNUMBER ':' tUNUMBER numzone",
781 "time : tUNUMBER ':' tUNUMBER ':' tUNUMBER o_merid",
782 "time : tUNUMBER ':' tUNUMBER ':' tUNUMBER numzone",
785 "zone : tZONE numzone",
787 "numzone : tSNUMBER",
788 "date : tUNUMBER '/' tUNUMBER",
789 "date : tUNUMBER '/' tUNUMBER '/' tUNUMBER",
790 "date : tMONTH tUNUMBER",
791 "date : tMONTH tUNUMBER ',' tUNUMBER",
792 "date : tUNUMBER tMONTH",
793 "date : tUNUMBER tMONTH tUNUMBER",
794 "date : tDAY ',' tUNUMBER tMONTH tUNUMBER",
795 "rel : tSNUMBER tSEC_UNIT",
796 "rel : tUNUMBER tSEC_UNIT",
797 "rel : tSNUMBER tMONTH_UNIT",
798 "rel : tUNUMBER tMONTH_UNIT",
799 "o_merid : /* empty */",
800 "o_merid : tMERIDIAN",
803 # line 1 "/usr/ccs/bin/yaccpar"
805 * Copyright (c) 1993 by Sun Microsystems, Inc.
808 #pragma ident "@(#)yaccpar 6.15 97/12/08 SMI"
811 ** Skeleton parser driver for yacc output
815 ** yacc user known macros and defines
817 #define YYERROR goto yyerrlab
818 #define YYACCEPT return(0)
819 #define YYABORT return(1)
820 #define YYBACKUP( newtoken, newvalue )\
822 if ( yychar >= 0 || ( yyr2[ yytmp ] >> 1 ) != 1 )\
824 yyerror( "syntax error - cannot backup" );\
832 #define YYRECOVERING() (!!yyerrflag)
833 #define YYNEW(type) malloc(sizeof(type) * yynewmax)
834 #define YYCOPY(to, from, type) \
835 (type *) memcpy(to, (char *) from, yymaxdepth * sizeof (type))
836 #define YYENLARGE( from, type) \
837 (type *) realloc((char *) from, yynewmax * sizeof(type))
839 # define YYDEBUG 1 /* make debugging available */
843 ** user known globals
845 int yydebug; /* set to 1 to get debugging */
848 ** driver internal defines
850 #define YYFLAG (-10000000)
853 ** global variables used by the parser
855 YYSTYPE *yypv; /* top of value stack */
856 int *yyps; /* top of state stack */
858 int yystate; /* current state */
859 int yytmp; /* extra var (lasts between blocks) */
861 int yynerrs; /* number of errors */
862 int yyerrflag; /* error recovery flag */
863 int yychar; /* current input token number */
868 #define YYLEX() yycvtok(yylex())
870 ** yycvtok - return a token if i is a wchar_t value that exceeds 255.
871 ** If i<255, i itself is the token. If i>255 but the neither
872 ** of the 30th or 31st bit is on, i is already a token.
874 #if defined(__STDC__) || defined(__cplusplus)
877 int yycvtok(i) int i;
881 int last = YYNMBCHARS - 1;
885 if(i&0x60000000){/*Must convert to a token. */
886 if( yymbchars[last].character < i ){
887 return i;/*Giving up*/
889 while ((last>=first)&&(first>=0)) {/*Binary search loop*/
890 mid = (first+last)/2;
891 j = yymbchars[mid].character;
893 return yymbchars[mid].tvalue;
900 /*No entry in the table.*/
901 return i;/* Giving up.*/
902 }else{/* i is already a token. */
907 #define YYLEX() yylex()
908 #endif/*!YYNMBCHARS*/
911 ** yyparse - return 0 if worked, 1 if syntax error not recovered from
913 #if defined(__STDC__) || defined(__cplusplus)
919 register YYSTYPE *yypvt = 0; /* top of value stack for $vars */
921 #if defined(__cplusplus) || defined(lint)
923 hacks to please C++ and lint - goto's inside
924 switch should never be executed
926 static int __yaccpar_lint_hack__ = 0;
927 switch (__yaccpar_lint_hack__)
929 case 1: goto yyerrlab;
930 case 2: goto yynewstate;
935 ** Initialize externals - yyparse may be called more than once
948 if ((yymaxdepth = YYEXPAND(0)) <= 0)
950 yyerror("yacc initialization error");
957 register YYSTYPE *yy_pv; /* top of value stack */
958 register int *yy_ps; /* top of state stack */
959 register int yy_state; /* current state */
960 register int yy_n; /* internal state number info */
961 goto yystack; /* moved from 6 lines above to here to please C++ */
964 ** get globals into registers.
965 ** branch to here only if YYBACKUP was called.
974 ** get globals into registers.
975 ** either we just started, or we just finished a reduction
983 ** top of for (;;) loop while no reductions done
987 ** put a state and value onto the stacks
991 ** if debugging, look up token value in list of value vs.
992 ** name pairs. 0 and negative (-1) are special values.
993 ** Note: linear search is used since time is not a real
994 ** consideration while debugging.
1000 printf( "State %d, token ", yy_state );
1002 printf( "end-of-file\n" );
1003 else if ( yychar < 0 )
1004 printf( "-none-\n" );
1007 for ( yy_i = 0; yytoks[yy_i].t_val >= 0;
1010 if ( yytoks[yy_i].t_val == yychar )
1013 printf( "%s\n", yytoks[yy_i].t_name );
1016 #endif /* YYDEBUG */
1017 if ( ++yy_ps >= &yys[ yymaxdepth ] ) /* room on stack? */
1020 ** reallocate and recover. Note that pointers
1021 ** have to be reset, or bad things will happen
1023 long yyps_index = (yy_ps - yys);
1024 long yypv_index = (yy_pv - yyv);
1025 long yypvt_index = (yypvt - yyv);
1028 yynewmax = YYEXPAND(yymaxdepth);
1030 yynewmax = 2 * yymaxdepth; /* double table size */
1031 if (yymaxdepth == YYMAXDEPTH) /* first time growth */
1033 char *newyys = (char *)YYNEW(int);
1034 char *newyyv = (char *)YYNEW(YYSTYPE);
1035 if (newyys != 0 && newyyv != 0)
1037 yys = YYCOPY(newyys, yys, int);
1038 yyv = YYCOPY(newyyv, yyv, YYSTYPE);
1041 yynewmax = 0; /* failed */
1043 else /* not first time */
1045 yys = YYENLARGE(yys, int);
1046 yyv = YYENLARGE(yyv, YYSTYPE);
1047 if (yys == 0 || yyv == 0)
1048 yynewmax = 0; /* failed */
1051 if (yynewmax <= yymaxdepth) /* tables not expanded */
1053 yyerror( "yacc stack overflow" );
1056 yymaxdepth = yynewmax;
1058 yy_ps = yys + yyps_index;
1059 yy_pv = yyv + yypv_index;
1060 yypvt = yyv + yypvt_index;
1066 ** we have a new state - find out what to do
1069 if ( ( yy_n = yypact[ yy_state ] ) <= YYFLAG )
1070 goto yydefault; /* simple state */
1073 ** if debugging, need to mark whether new token grabbed
1077 if ( ( yychar < 0 ) && ( ( yychar = YYLEX() ) < 0 ) )
1078 yychar = 0; /* reached EOF */
1080 if ( yydebug && yytmp )
1084 printf( "Received token " );
1086 printf( "end-of-file\n" );
1087 else if ( yychar < 0 )
1088 printf( "-none-\n" );
1091 for ( yy_i = 0; yytoks[yy_i].t_val >= 0;
1094 if ( yytoks[yy_i].t_val == yychar )
1097 printf( "%s\n", yytoks[yy_i].t_name );
1100 #endif /* YYDEBUG */
1101 if ( ( ( yy_n += yychar ) < 0 ) || ( yy_n >= YYLAST ) )
1103 if ( yychk[ yy_n = yyact[ yy_n ] ] == yychar ) /*valid shift*/
1108 if ( yyerrflag > 0 )
1114 if ( ( yy_n = yydef[ yy_state ] ) == -2 )
1119 if ( ( yychar < 0 ) && ( ( yychar = YYLEX() ) < 0 ) )
1120 yychar = 0; /* reached EOF */
1122 if ( yydebug && yytmp )
1126 printf( "Received token " );
1128 printf( "end-of-file\n" );
1129 else if ( yychar < 0 )
1130 printf( "-none-\n" );
1134 yytoks[yy_i].t_val >= 0;
1137 if ( yytoks[yy_i].t_val
1143 printf( "%s\n", yytoks[yy_i].t_name );
1146 #endif /* YYDEBUG */
1148 ** look through exception table
1151 register const int *yyxi = yyexca;
1153 while ( ( *yyxi != -1 ) ||
1154 ( yyxi[1] != yy_state ) )
1158 while ( ( *(yyxi += 2) >= 0 ) &&
1159 ( *yyxi != yychar ) )
1161 if ( ( yy_n = yyxi[1] ) < 0 )
1167 ** check for syntax error
1169 if ( yy_n == 0 ) /* have an error */
1171 /* no worry about speed here! */
1172 switch ( yyerrflag )
1174 case 0: /* new error */
1175 yyerror( "syntax error" );
1179 ** get globals into registers.
1180 ** we have a user generated syntax type error
1189 case 2: /* incompletely recovered error */
1193 ** find state where "error" is a legal
1196 while ( yy_ps >= yys )
1198 yy_n = yypact[ *yy_ps ] + YYERRCODE;
1199 if ( yy_n >= 0 && yy_n < YYLAST &&
1200 yychk[yyact[yy_n]] == YYERRCODE) {
1202 ** simulate shift of "error"
1204 yy_state = yyact[ yy_n ];
1208 ** current state has no shift on
1209 ** "error", pop stack
1212 # define _POP_ "Error recovery pops state %d, uncovers state %d\n"
1214 printf( _POP_, *yy_ps,
1222 ** there is no state on stack with "error" as
1223 ** a valid shift. give up.
1226 case 3: /* no shift yet; eat a token */
1229 ** if debugging, look up token in list of
1230 ** pairs. 0 and negative shouldn't occur,
1231 ** but since timing doesn't matter when
1232 ** debugging, it doesn't hurt to leave the
1239 printf( "Error recovery discards " );
1241 printf( "token end-of-file\n" );
1242 else if ( yychar < 0 )
1243 printf( "token -none-\n" );
1247 yytoks[yy_i].t_val >= 0;
1250 if ( yytoks[yy_i].t_val
1256 printf( "token %s\n",
1257 yytoks[yy_i].t_name );
1260 #endif /* YYDEBUG */
1261 if ( yychar == 0 ) /* reached EOF. quit */
1266 }/* end if ( yy_n == 0 ) */
1268 ** reduction by production yy_n
1269 ** put stack tops, etc. so things right after switch
1273 ** if debugging, print the string that is the user's
1274 ** specification of the reduction which is just about
1278 printf( "Reduce by (%d) \"%s\"\n",
1279 yy_n, yyreds[ yy_n ] );
1281 yytmp = yy_n; /* value to switch over */
1282 yypvt = yy_pv; /* $vars top of value stack */
1284 ** Look in goto table for next state
1285 ** Sorry about using yy_state here as temporary
1286 ** register variable, but why not, if it works...
1287 ** If yyr2[ yy_n ] doesn't have the low order bit
1288 ** set, then there is no action to be done for
1289 ** this reduction. So, no saving & unsaving of
1290 ** registers done. The only difference between the
1291 ** code just after the if and the body of the if is
1292 ** the goto yy_stack in the body. This way the test
1293 ** can be made before the choice of what to do is needed.
1296 /* length of production doubled with extra bit */
1297 register int yy_len = yyr2[ yy_n ];
1299 if ( !( yy_len & 01 ) )
1302 yyval = ( yy_pv -= yy_len )[1]; /* $$ = $1 */
1303 yy_state = yypgo[ yy_n = yyr1[ yy_n ] ] +
1304 *( yy_ps -= yy_len ) + 1;
1305 if ( yy_state >= YYLAST ||
1307 yyact[ yy_state ] ] != -yy_n )
1309 yy_state = yyact[ yypgo[ yy_n ] ];
1314 yyval = ( yy_pv -= yy_len )[1]; /* $$ = $1 */
1315 yy_state = yypgo[ yy_n = yyr1[ yy_n ] ] +
1316 *( yy_ps -= yy_len ) + 1;
1317 if ( yy_state >= YYLAST ||
1318 yychk[ yy_state = yyact[ yy_state ] ] != -yy_n )
1320 yy_state = yyact[ yypgo[ yy_n ] ];
1323 /* save until reenter driver code */
1329 ** code supplied by user is placed in this switch
1335 # line 118 "parsedate.y"
1339 /* I am compulsive about lint natterings... */
1340 if (yyHaveTime == -1) {
1346 # line 127 "parsedate.y"
1349 yyTimezone = yypvt[-0].Number;
1352 # line 131 "parsedate.y"
1357 # line 134 "parsedate.y"
1362 # line 139 "parsedate.y"
1364 if (yypvt[-1].Number < 100) {
1365 yyHour = yypvt[-1].Number;
1369 yyHour = yypvt[-1].Number / 100;
1370 yyMinutes = yypvt[-1].Number % 100;
1373 yyMeridian = yypvt[-0].Meridian;
1376 # line 151 "parsedate.y"
1378 yyHour = yypvt[-3].Number;
1379 yyMinutes = yypvt[-1].Number;
1381 yyMeridian = yypvt[-0].Meridian;
1384 # line 157 "parsedate.y"
1386 yyHour = yypvt[-3].Number;
1387 yyMinutes = yypvt[-1].Number;
1388 yyTimezone = yypvt[-0].Number;
1393 # line 164 "parsedate.y"
1395 yyHour = yypvt[-5].Number;
1396 yyMinutes = yypvt[-3].Number;
1397 yySeconds = yypvt[-1].Number;
1398 yyMeridian = yypvt[-0].Meridian;
1401 # line 170 "parsedate.y"
1403 yyHour = yypvt[-5].Number;
1404 yyMinutes = yypvt[-3].Number;
1405 yySeconds = yypvt[-1].Number;
1406 yyTimezone = yypvt[-0].Number;
1411 # line 180 "parsedate.y"
1413 yyval.Number = yypvt[-0].Number;
1417 # line 184 "parsedate.y"
1419 yyval.Number = yypvt[-0].Number;
1423 # line 188 "parsedate.y"
1425 /* Only allow "GMT+300" and "GMT-0800" */
1426 if (yypvt[-1].Number != 0) {
1429 yyval.Number = yypvt[-0].Number;
1433 # line 196 "parsedate.y"
1435 yyval.Number = yypvt[-0].Number;
1439 # line 202 "parsedate.y"
1443 /* Unix and GMT and numeric timezones -- a little confusing. */
1444 if (yypvt[-0].Number < 0) {
1445 /* Don't work with negative modulus. */
1446 yypvt[-0].Number = -yypvt[-0].Number;
1447 if (yypvt[-0].Number > 9999 || (i = yypvt[-0].Number % 100) >= 60) {
1450 yyval.Number = (yypvt[-0].Number / 100) * 60 + i;
1453 if (yypvt[-0].Number > 9999 || (i = yypvt[-0].Number % 100) >= 60) {
1456 yyval.Number = -((yypvt[-0].Number / 100) * 60 + i);
1460 # line 223 "parsedate.y"
1462 yyMonth = yypvt[-2].Number;
1463 yyDay = yypvt[-0].Number;
1466 # line 227 "parsedate.y"
1468 if (yypvt[-4].Number > 100) {
1469 yyYear = yypvt[-4].Number;
1470 yyMonth = yypvt[-2].Number;
1471 yyDay = yypvt[-0].Number;
1474 yyMonth = yypvt[-4].Number;
1475 yyDay = yypvt[-2].Number;
1476 yyYear = yypvt[-0].Number;
1480 # line 239 "parsedate.y"
1482 yyMonth = yypvt[-1].Number;
1483 yyDay = yypvt[-0].Number;
1486 # line 243 "parsedate.y"
1488 yyMonth = yypvt[-3].Number;
1489 yyDay = yypvt[-2].Number;
1490 yyYear = yypvt[-0].Number;
1493 # line 248 "parsedate.y"
1495 yyDay = yypvt[-1].Number;
1496 yyMonth = yypvt[-0].Number;
1499 # line 252 "parsedate.y"
1501 yyDay = yypvt[-2].Number;
1502 yyMonth = yypvt[-1].Number;
1503 yyYear = yypvt[-0].Number;
1506 # line 257 "parsedate.y"
1508 yyDay = yypvt[-2].Number;
1509 yyMonth = yypvt[-1].Number;
1510 yyYear = yypvt[-0].Number;
1513 # line 264 "parsedate.y"
1515 yyRelSeconds += yypvt[-1].Number * yypvt[-0].Number;
1518 # line 267 "parsedate.y"
1520 yyRelSeconds += yypvt[-1].Number * yypvt[-0].Number;
1523 # line 270 "parsedate.y"
1525 yyRelMonth += yypvt[-1].Number * yypvt[-0].Number;
1528 # line 273 "parsedate.y"
1530 yyRelMonth += yypvt[-1].Number * yypvt[-0].Number;
1533 # line 278 "parsedate.y"
1535 yyval.Meridian = MER24;
1538 # line 281 "parsedate.y"
1540 yyval.Meridian = yypvt[-0].Meridian;
1542 # line 531 "/usr/ccs/bin/yaccpar"
1544 goto yystack; /* reset registers in driver code */