📄 parsedate.y
字号:
%{/*** 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@bbn.com> and Jim Berets <jberets@bbn.com> in August, 1990.**** This code is in the public domain and has no copyright.*//* $Id: parsedate.y,v 1.34.2.8 2005/05/20 11:13:14 derick Exp $ */#include "php.h"#ifdef PHP_WIN32#include <malloc.h>#endif#include <stdio.h>#include <sys/types.h>#include <time.h>#include <ctype.h>#ifdef HAVE_SYS_TIME_H# include <sys/time.h>#endif#ifdef PHP_WIN32# include "win32/time.h"#endif#include "php_parsedate.h"#if HAVE_STDLIB_H# include <stdlib.h> /* for `free'; used by Bison 1.27 */#endif#if defined(_HPUX_SOURCE)#include <alloca.h>#endif#if defined (STDC_HEADERS) || (!defined (isascii) && !defined (HAVE_ISASCII))# define IN_CTYPE_DOMAIN(c) 1#else# define IN_CTYPE_DOMAIN(c) isascii(c)#endif#define ISSPACE(c) (IN_CTYPE_DOMAIN (c) && isspace (c))#define ISALPHA(c) (IN_CTYPE_DOMAIN (c) && isalpha (c))#define ISUPPER(c) (IN_CTYPE_DOMAIN (c) && isupper (c))#define ISDIGIT_LOCALE(c) (IN_CTYPE_DOMAIN (c) && isdigit (c))/* ISDIGIT differs from ISDIGIT_LOCALE, as follows: - Its arg may be any int or unsigned int; it need not be an unsigned char. - It's guaranteed to evaluate its argument exactly once. - It's typically faster. Posix 1003.2-1992 section 2.5.2.1 page 50 lines 1556-1558 says that only '0' through '9' are digits. Prefer ISDIGIT to ISDIGIT_LOCALE unless it's important to use the locale's definition of `digit' even when the host does not conform to Posix. */#define ISDIGIT(c) ((unsigned) (c) - '0' <= 9)#if defined (STDC_HEADERS) || defined (USG)# include <string.h>#endif#if __GNUC__ < 2 || (__GNUC__ == 2 && __GNUC_MINOR__ < 7)# define __attribute__(x)#endif#ifndef ATTRIBUTE_UNUSED# define ATTRIBUTE_UNUSED __attribute__ ((__unused__))#endif/* Some old versions of bison generate parsers that use bcopy. That loses on systems that don't provide the function, so we have to redefine it here. */#if !defined (HAVE_BCOPY) && defined (HAVE_MEMCPY) && !defined (bcopy)# define bcopy(from, to, len) memcpy ((to), (from), (len))#endif/* Remap normal yacc parser interface names (yyparse, yylex, yyerror, etc), as well as gratuitiously global symbol names, so we can have multiple yacc generated parsers in the same program. Note that these are only the variables produced by yacc. If other parser generators (bison, byacc, etc) produce additional global names that conflict at link time, then those parser generators need to be fixed instead of adding those names to this list. */#define yyparse php_gd_parse#define yylex php_gd_lexstatic int yyerror ();#define EPOCH 1970#define HOUR(x) ((x) * 60)#define MAX_BUFF_LEN 128 /* size of buffer to read the date into *//*** An entry in the lexical lookup table.*/typedef struct _TABLE { const char *name; int type; int value;} TABLE;/*** Meridian: am, pm, or 24-hour style.*/typedef enum _MERIDIAN { MERam, MERpm, MER24} MERIDIAN;struct date_yy { const char *yyInput; int yyDayOrdinal; int yyDayNumber; int yyHaveDate; int yyHaveDay; int yyHaveRel; int yyHaveTime; int yyHaveZone; int yyTimezone; int yyDay; int yyHour; int yyMinutes; int yyMonth; int yySeconds; int yyYear; MERIDIAN yyMeridian; int yyRelDay; int yyRelHour; int yyRelMinutes; int yyRelMonth; int yyRelSeconds; int yyRelYear;};typedef union _date_ll { int Number; enum _MERIDIAN Meridian;} date_ll;#define YYPARSE_PARAM parm#define YYLEX_PARAM parm#define YYSTYPE date_ll#define YYLTYPE void%}/* This grammar has 40 shift/reduce conflicts. */%expect 40%pure_parser%token tAGO tDAY tDAY_UNIT tDAYZONE tDST tHOUR_UNIT tID%token tMERIDIAN tMINUTE_UNIT tMONTH tMONTH_UNIT%token tSEC_UNIT tSNUMBER tUNUMBER tYEAR_UNIT tZONE%type <Number> tDAY tDAY_UNIT tDAYZONE tHOUR_UNIT tMINUTE_UNIT%type <Number> tMONTH tMONTH_UNIT%type <Number> tSEC_UNIT tSNUMBER tUNUMBER tYEAR_UNIT tZONE%type <Meridian> tMERIDIAN o_merid%%spec : /* NULL */ | spec item ;item : time { ((struct date_yy *)parm)->yyHaveTime++; } | zone { ((struct date_yy *)parm)->yyHaveZone++; } | date { ((struct date_yy *)parm)->yyHaveDate++; } | day { ((struct date_yy *)parm)->yyHaveDay++; } | rel { ((struct date_yy *)parm)->yyHaveRel++; } | number ;time : tUNUMBER tMERIDIAN { ((struct date_yy *)parm)->yyHour = $1; ((struct date_yy *)parm)->yyMinutes = 0; ((struct date_yy *)parm)->yySeconds = 0; ((struct date_yy *)parm)->yyMeridian = $2;#ifdef PHP_DEBUG_PARSE_DATE_PARSER printf("[U M]\n");#endif } | tUNUMBER ':' tUNUMBER o_merid { ((struct date_yy *)parm)->yyHour = $1; ((struct date_yy *)parm)->yyMinutes = $3; ((struct date_yy *)parm)->yySeconds = 0; ((struct date_yy *)parm)->yyMeridian = $4;#ifdef PHP_DEBUG_PARSE_DATE_PARSER printf("[U:U M]\n");#endif } | tUNUMBER ':' tUNUMBER rel { ((struct date_yy *)parm)->yyHour = $1; ((struct date_yy *)parm)->yyMinutes = $3; ((struct date_yy *)parm)->yyMeridian = MER24;#ifdef PHP_DEBUG_PARSE_DATE_PARSER printf("[U:U rel]\n");#endif } | tUNUMBER ':' tUNUMBER tSNUMBER { ((struct date_yy *)parm)->yyHour = $1; ((struct date_yy *)parm)->yyMinutes = $3; ((struct date_yy *)parm)->yyMeridian = MER24; ((struct date_yy *)parm)->yyHaveZone++; ((struct date_yy *)parm)->yyTimezone = ($4 < 0 ? -$4 % 100 + (-$4 / 100) * 60 : - ($4 % 100 + ($4 / 100) * 60));#ifdef PHP_DEBUG_PARSE_DATE_PARSER printf("[U:U S]\n");#endif } | tUNUMBER ':' tUNUMBER ':' tUNUMBER o_merid { ((struct date_yy *)parm)->yyHour = $1; ((struct date_yy *)parm)->yyMinutes = $3; ((struct date_yy *)parm)->yySeconds = $5; ((struct date_yy *)parm)->yyMeridian = $6;#ifdef PHP_DEBUG_PARSE_DATE_PARSER printf("[U:U:U M]\n");#endif } | tUNUMBER ':' tUNUMBER ':' tUNUMBER rel { /* ISO 8601 format. hh:mm:ss[+-][0-9]{2}([0-9]{2})?. */ ((struct date_yy *)parm)->yyHour = $1; ((struct date_yy *)parm)->yyMinutes = $3; ((struct date_yy *)parm)->yySeconds = $5;#ifdef PHP_DEBUG_PARSE_DATE_PARSER printf("[U:U:U rel]\n");#endif } | tUNUMBER ':' tUNUMBER ':' tUNUMBER tSNUMBER { /* ISO 8601 format. hh:mm:ss[+-][0-9]{2}([0-9]{2})?. */ ((struct date_yy *)parm)->yyHour = $1; ((struct date_yy *)parm)->yyMinutes = $3; ((struct date_yy *)parm)->yySeconds = $5; ((struct date_yy *)parm)->yyMeridian = MER24; ((struct date_yy *)parm)->yyHaveZone++; if ($6 <= -100 || $6 >= 100) { ((struct date_yy *)parm)->yyTimezone = -$6 % 100 + (-$6 / 100) * 60; } else { ((struct date_yy *)parm)->yyTimezone = -$6 * 60; }#ifdef PHP_DEBUG_PARSE_DATE_PARSER printf("[U:U:U S]\n");#endif } ;zone : tZONE { ((struct date_yy *)parm)->yyTimezone = $1; } | tDAYZONE { ((struct date_yy *)parm)->yyTimezone = $1 - 60; } | tZONE tDST { ((struct date_yy *)parm)->yyTimezone = $1 - 60; } ;day : tDAY { ((struct date_yy *)parm)->yyDayOrdinal = 1; ((struct date_yy *)parm)->yyDayNumber = $1; } | tDAY ',' { ((struct date_yy *)parm)->yyDayOrdinal = 1; ((struct date_yy *)parm)->yyDayNumber = $1; } | tUNUMBER tDAY { ((struct date_yy *)parm)->yyDayOrdinal = $1; ((struct date_yy *)parm)->yyDayNumber = $2; } ;date : tUNUMBER '/' tUNUMBER { ((struct date_yy *)parm)->yyMonth = $1; ((struct date_yy *)parm)->yyDay = $3; } | tMONTH tUNUMBER tUNUMBER ':' tUNUMBER ':' tUNUMBER tUNUMBER { ((struct date_yy *)parm)->yyYear = $8; ((struct date_yy *)parm)->yyMonth = $1; ((struct date_yy *)parm)->yyDay = $2; ((struct date_yy *)parm)->yyHour = $3; ((struct date_yy *)parm)->yyMinutes = $5; ((struct date_yy *)parm)->yySeconds = $7; ((struct date_yy *)parm)->yyHaveTime = 1; } | tUNUMBER '/' tUNUMBER '/' tUNUMBER { /* Interpret as YYYY/MM/DD if $1 >= 1000, otherwise as MM/DD/YY. The goal in recognizing YYYY/MM/DD is solely to support legacy machine-generated dates like those in an RCS log listing. If you want portability, use the ISO 8601 format. */ if ($1 >= 1000) { ((struct date_yy *)parm)->yyYear = $1; ((struct date_yy *)parm)->yyMonth = $3; ((struct date_yy *)parm)->yyDay = $5; } else { ((struct date_yy *)parm)->yyMonth = $1; ((struct date_yy *)parm)->yyDay = $3; ((struct date_yy *)parm)->yyYear = $5; } } | tUNUMBER tSNUMBER tSNUMBER { /* ISO 8601 format. yyyy-mm-dd. */ ((struct date_yy *)parm)->yyYear = $1; ((struct date_yy *)parm)->yyMonth = -$2; ((struct date_yy *)parm)->yyDay = -$3; } | tUNUMBER tMONTH tSNUMBER { /* e.g. 17-JUN-1992. */ ((struct date_yy *)parm)->yyDay = $1; ((struct date_yy *)parm)->yyMonth = $2; ((struct date_yy *)parm)->yyYear = -$3; } | tMONTH tUNUMBER tUNUMBER { ((struct date_yy *)parm)->yyMonth = $1; ((struct date_yy *)parm)->yyDay = $2; ((struct date_yy *)parm)->yyYear = $3; } | tMONTH tUNUMBER { ((struct date_yy *)parm)->yyMonth = $1; if ($2 > 1000) { ((struct date_yy *)parm)->yyYear = $2; } else { ((struct date_yy *)parm)->yyDay = $2; } } | tMONTH tUNUMBER ',' tUNUMBER { ((struct date_yy *)parm)->yyMonth = $1; ((struct date_yy *)parm)->yyDay = $2; ((struct date_yy *)parm)->yyYear = $4; } | tUNUMBER tMONTH { ((struct date_yy *)parm)->yyMonth = $2; if ($1 > 1000) { ((struct date_yy *)parm)->yyYear = $1; } else { ((struct date_yy *)parm)->yyDay = $1; } } | tUNUMBER tMONTH tUNUMBER { ((struct date_yy *)parm)->yyMonth = $2; ((struct date_yy *)parm)->yyDay = $1; ((struct date_yy *)parm)->yyYear = $3; } ;rel : relunit tAGO { ((struct date_yy *)parm)->yyRelSeconds = -((struct date_yy *)parm)->yyRelSeconds; ((struct date_yy *)parm)->yyRelMinutes = -((struct date_yy *)parm)->yyRelMinutes; ((struct date_yy *)parm)->yyRelHour = -((struct date_yy *)parm)->yyRelHour; ((struct date_yy *)parm)->yyRelDay = -((struct date_yy *)parm)->yyRelDay; ((struct date_yy *)parm)->yyRelMonth = -((struct date_yy *)parm)->yyRelMonth; ((struct date_yy *)parm)->yyRelYear = -((struct date_yy *)parm)->yyRelYear; } | relunit ;relunit : tUNUMBER tYEAR_UNIT { ((struct date_yy *)parm)->yyRelYear += $1 * $2; } | tSNUMBER tYEAR_UNIT { ((struct date_yy *)parm)->yyRelYear += $1 * $2; } | tYEAR_UNIT { ((struct date_yy *)parm)->yyRelYear += $1; } | tUNUMBER tMONTH_UNIT { ((struct date_yy *)parm)->yyRelMonth += $1 * $2; } | tSNUMBER tMONTH_UNIT { ((struct date_yy *)parm)->yyRelMonth += $1 * $2; } | tMONTH_UNIT { ((struct date_yy *)parm)->yyRelMonth += $1; } | tUNUMBER tDAY_UNIT { ((struct date_yy *)parm)->yyRelDay += $1 * $2; } | tSNUMBER tDAY_UNIT { ((struct date_yy *)parm)->yyRelDay += $1 * $2; } | tDAY_UNIT { ((struct date_yy *)parm)->yyRelDay += $1; } | tUNUMBER tHOUR_UNIT { ((struct date_yy *)parm)->yyRelHour += $1 * $2; } | tSNUMBER tHOUR_UNIT { ((struct date_yy *)parm)->yyRelHour += $1 * $2; } | tHOUR_UNIT { ((struct date_yy *)parm)->yyRelHour += $1; } | tUNUMBER tMINUTE_UNIT { ((struct date_yy *)parm)->yyRelMinutes += $1 * $2; } | tSNUMBER tMINUTE_UNIT { ((struct date_yy *)parm)->yyRelMinutes += $1 * $2; } | tMINUTE_UNIT { ((struct date_yy *)parm)->yyRelMinutes += $1; } | tUNUMBER tSEC_UNIT { ((struct date_yy *)parm)->yyRelSeconds += $1 * $2; } | tSNUMBER tSEC_UNIT { ((struct date_yy *)parm)->yyRelSeconds += $1 * $2; } | tSEC_UNIT { ((struct date_yy *)parm)->yyRelSeconds += $1; } ;number : tUNUMBER { if (((struct date_yy *)parm)->yyHaveTime && ((struct date_yy *)parm)->yyHaveDate && !((struct date_yy *)parm)->yyHaveRel) ((struct date_yy *)parm)->yyYear = $1; else { if ($1>10000) { ((struct date_yy *)parm)->yyHaveDate++; ((struct date_yy *)parm)->yyDay= ($1)%100; ((struct date_yy *)parm)->yyMonth= ($1/100)%100; ((struct date_yy *)parm)->yyYear = $1/10000; } else { ((struct date_yy *)parm)->yyHaveTime++; if ($1 < 100) { ((struct date_yy *)parm)->yyHour = $1; ((struct date_yy *)parm)->yyMinutes = 0; } else { ((struct date_yy *)parm)->yyHour = $1 / 100; ((struct date_yy *)parm)->yyMinutes = $1 % 100; } ((struct date_yy *)parm)->yySeconds = 0; ((struct date_yy *)parm)->yyMeridian = MER24; } } } ;o_merid : /* NULL */ { $$ = MER24; } | tMERIDIAN { $$ = $1; } ;%%time_t get_date (char *p, time_t *now);#ifndef PHP_WIN32extern struct tm *gmtime();extern struct tm *localtime();extern time_t mktime();#endif/* Month and day table. */static TABLE const 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 }, { "sept", tMONTH, 9 }, { "october", tMONTH, 10 }, { "november", tMONTH, 11 }, { "december", tMONTH, 12 }, { "sunday", tDAY, 0 }, { "monday", tDAY, 1 }, { "tuesday", tDAY, 2 }, { "tues", tDAY, 2 }, { "wednesday", tDAY, 3 }, { "wednes", tDAY, 3 }, { "thursday", tDAY, 4 }, { "thur", tDAY, 4 }, { "thurs", tDAY, 4 }, { "friday", tDAY, 5 }, { "saturday", tDAY, 6 }, { NULL, 0, 0 }};/* Time units table. */static TABLE const UnitsTable[] = { { "year", tYEAR_UNIT, 1 }, { "month", tMONTH_UNIT, 1 }, { "fortnight", tDAY_UNIT, 14 }, { "week", tDAY_UNIT, 7 }, { "day", tDAY_UNIT, 1 }, { "hour", tHOUR_UNIT, 1 }, { "minute", tMINUTE_UNIT, 1 }, { "min", tMINUTE_UNIT, 1 }, { "second", tSEC_UNIT, 1 }, { "sec", tSEC_UNIT, 1 }, { NULL, 0, 0 }};/* Assorted relative-time words. */static TABLE const OtherTable[] = { { "tomorrow", tDAY_UNIT, 1 },
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -