📄 date.y
字号:
%{/* * Project : tin - a Usenet reader * Module : parsedate.y * Author : S.Bellovin & R.$alz & J.Berets & P.Eggert * Created : 01-08-90 * Updated : 04-12-92 * Notes : This grammar has 11 shift/reduce conflicts. * Originally written by Steven M. Bellovin <smb@research.att.com> * while at the University of North Carolina at Chapel Hill. * Later tweaked by a couple of people on Usenet. Completely * overhauled by Rich $alz <rsalz@osf.org> and Jim Berets * <jberets@bbn.com> in August, 1990. * Further revised (removed obsolete constructs and cleaned up * timezone names) in August, 1991, by Rich. * Paul Eggert <eggert@twinsun.com> helped in September 1992. * Further changes by Evgeny Stambulchik; mostly workarounds * to make the code more tolerable. 2000-2001 * Revision : 1.13 * Copyright : This code is in the public domain and has no copyright. *//* SUPPRESS 530 *//* Empty body for statement *//* SUPPRESS 593 on yyerrlab *//* Label was not used *//* SUPPRESS 593 on yynewstate *//* Label was not used *//* SUPPRESS 595 on yypvt *//* Automatic variable may be used before set */#include "date.h"/*** Get the number of elements in a fixed-size array, or a pointer just** past the end of it.*/#define SIZEOF(array) ((int)(sizeof array / sizeof array[0]))#define ENDOF(array) (&array[SIZEOF(array)])#define CTYPE(isXXXXX, c) ((isascii((c)) && isXXXXX((c))))typedef char *STRING;#define yyparse date_parse#define yylex date_lex#define yyerror date_error /* See the LeapYears table in Convert. */#define EPOCH 1970#define END_OF_TIME 2038 /* Constants for general time calculations. */#define DST_OFFSET 1#define SECSPERDAY (24L * 60L * 60L) /* Readability for TABLE stuff. */#define HOUR(x) (x * 60)#define LPAREN '('#define RPAREN ')'#define IS7BIT(x) ((unsigned int)(x) < 0200)/*** An entry in the lexical lookup table.*/typedef struct _TABLE { STRING name; int type; time_t value;} TABLE;/*** Daylight-savings mode: on, off, or not yet known.*/typedef enum _DSTMODE { DSTon, DSToff, DSTmaybe} DSTMODE;/*** Meridian: am, pm, or 24-hour style.*/typedef enum _MERIDIAN { MERam, MERpm, MER24} MERIDIAN;/*** Global variables. We could get rid of most of them by using a yacc** union, but this is more efficient. (This routine predates the** yacc %union construct.)*/static char *yyInput;static DSTMODE yyDSTmode;static int yyHaveDate;static int yyHaveRel;static int yyHaveTime;static time_t yyTimezone;static time_t yyDay;static time_t yyHour;static time_t yyMinutes;static time_t yyMonth;static time_t yySeconds;static time_t yyYear;static MERIDIAN yyMeridian;static time_t yyRelMonth;static time_t yyRelSeconds;extern struct tm *localtime();static void date_error();%}%union { time_t Number; enum _MERIDIAN Meridian;}%token tDAY tDAYZONE tMERIDIAN tMONTH tMONTH_UNIT tSEC_UNIT%token tUNUMBER tUNKNOWN tZONE%type <Number> tDAYZONE tMONTH tMONTH_UNIT tSEC_UNIT%type <Number> tUNUMBER tZONE s_number numzone zone qzone%type <Meridian> tMERIDIAN o_merid%%spec : /* NULL */ | spec item ;item : time { yyHaveTime++;#if defined(lint) /* I am compulsive about lint natterings... */ if (yyHaveTime == -1) { YYERROR; }#endif /* defined(lint) */ } | time zone { yyHaveTime++; yyTimezone = $2; } | time qzone { yyHaveTime++; yyTimezone = $2; } | time junkzone { yyHaveTime++; } | date { yyHaveDate++; } | rel { yyHaveRel = 1; } ;time : tUNUMBER o_merid { if ($1 < 100) { yyHour = $1; yyMinutes = 0; } else { yyHour = $1 / 100; yyMinutes = $1 % 100; } yySeconds = 0; yyMeridian = $2; } | tUNUMBER ':' tUNUMBER o_merid { yyHour = $1; yyMinutes = $3; yySeconds = 0; yyMeridian = $4; } | tUNUMBER ':' tUNUMBER numzone { yyHour = $1; yyMinutes = $3; yyTimezone = $4; yyMeridian = MER24; yyDSTmode = DSToff; } | tUNUMBER ':' tUNUMBER ':' tUNUMBER o_merid { yyHour = $1; yyMinutes = $3; yySeconds = $5; yyMeridian = $6; } | tUNUMBER ':' tUNUMBER ':' tUNUMBER numzone { yyHour = $1; yyMinutes = $3; yySeconds = $5; yyTimezone = $6; yyMeridian = MER24; yyDSTmode = DSToff; } ;zone : tZONE { $$ = $1; yyDSTmode = DSToff; } | tDAYZONE { $$ = $1; yyDSTmode = DSTon; } | tZONE numzone { /* Only allow "GMT+300" and "GMT-0800" */ if ($1 != 0) { YYABORT; } $$ = $2; yyDSTmode = DSToff; } | numzone { $$ = $1; yyDSTmode = DSToff; } ;qzone : '"' zone '"' { $$ = $2; }junkzone : tUNKNOWN { } | tUNKNOWN tUNKNOWN { } | tUNKNOWN tUNKNOWN tUNKNOWN { }numzone : s_number { int i; /* Unix and GMT and numeric timezones -- a little confusing. */ if ($1 < 0) { /* Don't work with negative modulus. */ $1 = -$1; if ($1 > 9999 || (i = $1 % 100) >= 60) { YYABORT; } $$ = ($1 / 100) * 60 + i; } else { if ($1 > 9999 || (i = $1 % 100) >= 60) { YYABORT; } $$ = -(($1 / 100) * 60 + i); } } ;date : tUNUMBER '/' tUNUMBER { yyMonth = $1; yyDay = $3; } | tUNUMBER '/' tUNUMBER '/' tUNUMBER { if ($1 > 100) { yyYear = $1; yyMonth = $3; yyDay = $5; } else { yyMonth = $1; yyDay = $3; yyYear = $5; } } | tUNUMBER '-' tUNUMBER '-' tUNUMBER { yyYear = $1; yyMonth = $3; yyDay = $5; } | tMONTH tUNUMBER { yyMonth = $1; yyDay = $2; } | tMONTH tUNUMBER ',' tUNUMBER { yyMonth = $1; yyDay = $2; yyYear = $4; } | tUNUMBER tMONTH { yyDay = $1; yyMonth = $2; } | tUNUMBER tMONTH tUNUMBER { yyDay = $1; yyMonth = $2; yyYear = $3; } | tDAY ',' tUNUMBER tMONTH tUNUMBER { yyDay = $3; yyMonth = $4; yyYear = $5; } ;rel : s_number tSEC_UNIT { yyRelSeconds += $1 * $2; } | tUNUMBER tSEC_UNIT { yyRelSeconds += $1 * $2; } | s_number tMONTH_UNIT { yyRelMonth += $1 * $2; } | tUNUMBER tMONTH_UNIT { yyRelMonth += $1 * $2; } ;o_merid : /* NULL */ { $$ = MER24; } | tMERIDIAN { $$ = $1; } ;s_number : '-' tUNUMBER { $$ = -$2; } | '+' tUNUMBER { $$ = $2; }%%/* Month and day table. */static TABLE MonthDayTable[] = { { "january", tMONTH, 1 }, { "february", tMONTH, 2 }, { "march", tMONTH, 3 }, { "april", tMONTH, 4 }, { "may", tMONTH, 5 }, { "june", tMONTH, 6 }, { "july", tMONTH, 7 }, { "august", tMONTH, 8 }, { "september", tMONTH, 9 }, { "october", tMONTH, 10 }, { "november", tMONTH, 11 }, { "december", tMONTH, 12 }, /* The value of the day isn't used... */ { "sunday", tDAY, 0 }, { "monday", tDAY, 0 }, { "tuesday", tDAY, 0 }, { "wednesday", tDAY, 0 }, { "thursday", tDAY, 0 }, { "friday", tDAY, 0 }, { "saturday", tDAY, 0 },};/* Time units table. */static TABLE UnitsTable[] = { { "year", tMONTH_UNIT, 12 }, { "month", tMONTH_UNIT, 1 }, { "week", tSEC_UNIT, 7 * 24 * 60 * 60 }, { "day", tSEC_UNIT, 1 * 24 * 60 * 60 }, { "hour", tSEC_UNIT, 60 * 60 }, { "minute", tSEC_UNIT, 60 }, { "min", tSEC_UNIT, 60 }, { "second", tSEC_UNIT, 1 }, { "sec", tSEC_UNIT, 1 },};/* Timezone table. */static TABLE TimezoneTable[] = { { "gmt", tZONE, HOUR( 0) }, /* Greenwich Mean */ { "ut", tZONE, HOUR( 0) }, /* Universal */ { "utc", tZONE, HOUR( 0) }, /* Universal Coordinated */ { "cut", tZONE, HOUR( 0) }, /* Coordinated Universal */ { "z", tZONE, HOUR( 0) }, /* Greenwich Mean */ { "wet", tZONE, HOUR( 0) }, /* Western European */ { "bst", tDAYZONE, HOUR( 0) }, /* British Summer */ { "nst", tZONE, HOUR(3)+30 }, /* Newfoundland Standard */ { "ndt", tDAYZONE, HOUR(3)+30 }, /* Newfoundland Daylight */ { "ast", tZONE, HOUR( 4) }, /* Atlantic Standard */ { "adt", tDAYZONE, HOUR( 4) }, /* Atlantic Daylight */ { "est", tZONE, HOUR( 5) }, /* Eastern Standard */ { "edt", tDAYZONE, HOUR( 5) }, /* Eastern Daylight */ { "cst", tZONE, HOUR( 6) }, /* Central Standard */ { "cdt", tDAYZONE, HOUR( 6) }, /* Central Daylight */ { "mst", tZONE, HOUR( 7) }, /* Mountain Standard */ { "mdt", tDAYZONE, HOUR( 7) }, /* Mountain Daylight */ { "pst", tZONE, HOUR( 8) }, /* Pacific Standard */ { "pdt", tDAYZONE, HOUR( 8) }, /* Pacific Daylight */ { "yst", tZONE, HOUR( 9) }, /* Yukon Standard */ { "ydt", tDAYZONE, HOUR( 9) }, /* Yukon Daylight */ { "akst", tZONE, HOUR( 9) }, /* Alaska Standard */ { "akdt", tDAYZONE, HOUR( 9) }, /* Alaska Daylight */ { "hst", tZONE, HOUR(10) }, /* Hawaii Standard */ { "hast", tZONE, HOUR(10) }, /* Hawaii-Aleutian Standard */ { "hadt", tDAYZONE, HOUR(10) }, /* Hawaii-Aleutian Daylight */ { "ces", tDAYZONE, -HOUR(1) }, /* Central European Summer */ { "cest", tDAYZONE, -HOUR(1) }, /* Central European Summer */ { "mez", tZONE, -HOUR(1) }, /* Middle European */ { "mezt", tDAYZONE, -HOUR(1) }, /* Middle European Summer */ { "cet", tZONE, -HOUR(1) }, /* Central European */ { "met", tZONE, -HOUR(1) }, /* Middle European */ { "eet", tZONE, -HOUR(2) }, /* Eastern Europe */ { "msk", tZONE, -HOUR(3) }, /* Moscow Winter */ { "msd", tDAYZONE, -HOUR(3) }, /* Moscow Summer */ { "wast", tZONE, -HOUR(8) }, /* West Australian Standard */ { "wadt", tDAYZONE, -HOUR(8) }, /* West Australian Daylight */ { "hkt", tZONE, -HOUR(8) }, /* Hong Kong */ { "cct", tZONE, -HOUR(8) }, /* China Coast */ { "jst", tZONE, -HOUR(9) }, /* Japan Standard */ { "kst", tZONE, -HOUR(9) }, /* Korean Standard */ { "kdt", tZONE, -HOUR(9) }, /* Korean Daylight */ { "cast", tZONE, -(HOUR(9)+30) }, /* Central Australian Standard */ { "cadt", tDAYZONE, -(HOUR(9)+30) }, /* Central Australian Daylight */ { "east", tZONE, -HOUR(10) }, /* Eastern Australian Standard */ { "eadt", tDAYZONE, -HOUR(10) }, /* Eastern Australian Daylight */ { "nzst", tZONE, -HOUR(12) }, /* New Zealand Standard */ { "nzdt", tDAYZONE, -HOUR(12) }, /* New Zealand Daylight */ /* For completeness we include the following entries. */#if 0 /* Duplicate names. Either they conflict with a zone listed above * (which is either more likely to be seen or just been in circulation * longer), or they conflict with another zone in this section and * we could not reasonably choose one over the other. */ { "fst", tZONE, HOUR( 2) }, /* Fernando De Noronha Standard */ { "fdt", tDAYZONE, HOUR( 2) }, /* Fernando De Noronha Daylight */ { "bst", tZONE, HOUR( 3) }, /* Brazil Standard */ { "est", tZONE, HOUR( 3) }, /* Eastern Standard (Brazil) */ { "edt", tDAYZONE, HOUR( 3) }, /* Eastern Daylight (Brazil) */ { "wst", tZONE, HOUR( 4) }, /* Western Standard (Brazil) */ { "wdt", tDAYZONE, HOUR( 4) }, /* Western Daylight (Brazil) */ { "cst", tZONE, HOUR( 5) }, /* Chile Standard */ { "cdt", tDAYZONE, HOUR( 5) }, /* Chile Daylight */ { "ast", tZONE, HOUR( 5) }, /* Acre Standard */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -