diff options
-rw-r--r-- | ChangeLog | 11 | ||||
-rw-r--r-- | generic/tclDate.c | 532 | ||||
-rw-r--r-- | generic/tclGetDate.y | 212 | ||||
-rw-r--r-- | library/clock.tcl | 4 | ||||
-rw-r--r-- | tests/clock.test | 43 |
5 files changed, 516 insertions, 286 deletions
@@ -1,3 +1,14 @@ +2006-06-09 Kevin B. Kenny <kennykb@acm.org> + + * generic/tclGetDate.y: Fixed a thread safety bug in the generated + * library/clock.tcl: Bison parser (needed a %pure-parser + * tests/clock.test: declaration to avoid static variables). + Discovered that the %pure-parser declaration + allowed for returning the Bison error message + to the Tcl caller in the event of a syntax + error, so did so. + * generic/tclDate.c: bison 2.3 + 2006-06-08 Kevin B. Kenny <kennykb@acm.org> * library/tzdata/Asia/Dhaka: New DST rule for Bangladesh. diff --git a/generic/tclDate.c b/generic/tclDate.c index 94b3caf..432225d 100644 --- a/generic/tclDate.c +++ b/generic/tclDate.c @@ -53,10 +53,10 @@ #define YYSKELETON_NAME "yacc.c" /* Pure parsers. */ -#define YYPURE 0 +#define YYPURE 1 /* Using locations. */ -#define YYLSP_NEEDED 0 +#define YYLSP_NEEDED 1 /* Substitute the variable and function names. */ #define yyparse TclDateparse @@ -66,7 +66,7 @@ #define yychar TclDatechar #define yydebug TclDatedebug #define yynerrs TclDatenerrs - +#define yylloc TclDatelloc /* Tokens. */ #ifndef YYTOKENTYPE @@ -79,19 +79,18 @@ tDAYZONE = 260, tID = 261, tMERIDIAN = 262, - tMINUTE_UNIT = 263, - tMONTH = 264, - tMONTH_UNIT = 265, - tSTARDATE = 266, - tSEC_UNIT = 267, - tSNUMBER = 268, - tUNUMBER = 269, - tZONE = 270, - tEPOCH = 271, - tDST = 272, - tISOBASE = 273, - tDAY_UNIT = 274, - tNEXT = 275 + tMONTH = 263, + tMONTH_UNIT = 264, + tSTARDATE = 265, + tSEC_UNIT = 266, + tSNUMBER = 267, + tUNUMBER = 268, + tZONE = 269, + tEPOCH = 270, + tDST = 271, + tISOBASE = 272, + tDAY_UNIT = 273, + tNEXT = 274 }; #endif /* Tokens. */ @@ -100,19 +99,18 @@ #define tDAYZONE 260 #define tID 261 #define tMERIDIAN 262 -#define tMINUTE_UNIT 263 -#define tMONTH 264 -#define tMONTH_UNIT 265 -#define tSTARDATE 266 -#define tSEC_UNIT 267 -#define tSNUMBER 268 -#define tUNUMBER 269 -#define tZONE 270 -#define tEPOCH 271 -#define tDST 272 -#define tISOBASE 273 -#define tDAY_UNIT 274 -#define tNEXT 275 +#define tMONTH 263 +#define tMONTH_UNIT 264 +#define tSTARDATE 265 +#define tSEC_UNIT 266 +#define tSNUMBER 267 +#define tUNUMBER 268 +#define tZONE 269 +#define tEPOCH 270 +#define tDST 271 +#define tISOBASE 272 +#define tDAY_UNIT 273 +#define tNEXT 274 @@ -133,7 +131,6 @@ * this file, and for a DISCLAIMER OF ALL WARRANTIES. * */ - #include "tclInt.h" /* @@ -151,6 +148,10 @@ */ typedef struct DateInfo { + + Tcl_Obj* messages; /* Error messages */ + const char* separatrix; /* String separating messages */ + time_t dateYear; time_t dateMonth; time_t dateDay; @@ -178,42 +179,40 @@ typedef struct DateInfo { time_t dateDayNumber; int dateHaveDay; + const char *dateStart; const char *dateInput; time_t *dateRelPointer; int dateDigitCount; } DateInfo; -#define YYPARSE_PARAM info -#define YYLEX_PARAM info - #define YYMALLOC ckalloc #define YYFREE(x) (ckfree((void*) (x))) -#define yyDSTmode (((DateInfo *) info)->dateDSTmode) -#define yyDayOrdinal (((DateInfo *) info)->dateDayOrdinal) -#define yyDayNumber (((DateInfo *) info)->dateDayNumber) -#define yyMonthOrdinal (((DateInfo *) info)->dateMonthOrdinal) -#define yyHaveDate (((DateInfo *) info)->dateHaveDate) -#define yyHaveDay (((DateInfo *) info)->dateHaveDay) -#define yyHaveOrdinalMonth (((DateInfo *) info)->dateHaveOrdinalMonth) -#define yyHaveRel (((DateInfo *) info)->dateHaveRel) -#define yyHaveTime (((DateInfo *) info)->dateHaveTime) -#define yyHaveZone (((DateInfo *) info)->dateHaveZone) -#define yyTimezone (((DateInfo *) info)->dateTimezone) -#define yyDay (((DateInfo *) info)->dateDay) -#define yyMonth (((DateInfo *) info)->dateMonth) -#define yyYear (((DateInfo *) info)->dateYear) -#define yyHour (((DateInfo *) info)->dateHour) -#define yyMinutes (((DateInfo *) info)->dateMinutes) -#define yySeconds (((DateInfo *) info)->dateSeconds) -#define yyMeridian (((DateInfo *) info)->dateMeridian) -#define yyRelMonth (((DateInfo *) info)->dateRelMonth) -#define yyRelDay (((DateInfo *) info)->dateRelDay) -#define yyRelSeconds (((DateInfo *) info)->dateRelSeconds) -#define yyRelPointer (((DateInfo *) info)->dateRelPointer) -#define yyInput (((DateInfo *) info)->dateInput) -#define yyDigitCount (((DateInfo *) info)->dateDigitCount) +#define yyDSTmode (info->dateDSTmode) +#define yyDayOrdinal (info->dateDayOrdinal) +#define yyDayNumber (info->dateDayNumber) +#define yyMonthOrdinal (info->dateMonthOrdinal) +#define yyHaveDate (info->dateHaveDate) +#define yyHaveDay (info->dateHaveDay) +#define yyHaveOrdinalMonth (info->dateHaveOrdinalMonth) +#define yyHaveRel (info->dateHaveRel) +#define yyHaveTime (info->dateHaveTime) +#define yyHaveZone (info->dateHaveZone) +#define yyTimezone (info->dateTimezone) +#define yyDay (info->dateDay) +#define yyMonth (info->dateMonth) +#define yyYear (info->dateYear) +#define yyHour (info->dateHour) +#define yyMinutes (info->dateMinutes) +#define yySeconds (info->dateSeconds) +#define yyMeridian (info->dateMeridian) +#define yyRelMonth (info->dateRelMonth) +#define yyRelDay (info->dateRelDay) +#define yyRelSeconds (info->dateRelSeconds) +#define yyRelPointer (info->dateRelPointer) +#define yyInput (info->dateInput) +#define yyDigitCount (info->dateDigitCount) #define EPOCH 1970 #define START_OF_TIME 1902 @@ -256,17 +255,6 @@ typedef enum _MERIDIAN { MERam, MERpm, MER24 } MERIDIAN; -/* - * Prototypes of internal functions. - */ - -static int LookupWord(char *buff); -static void TclDateerror(const char *s); -static int TclDatelex(void *info); -static time_t ToSeconds(time_t Hours, time_t Minutes, - time_t Seconds, MERIDIAN Meridian); -MODULE_SCOPE int yyparse(void *); - /* Enabling traces. */ @@ -302,11 +290,39 @@ typedef union YYSTYPE # define YYSTYPE_IS_TRIVIAL 1 #endif +#if ! defined YYLTYPE && ! defined YYLTYPE_IS_DECLARED +typedef struct YYLTYPE +{ + int first_line; + int first_column; + int last_line; + int last_column; +} YYLTYPE; +# define yyltype YYLTYPE /* obsolescent; will be withdrawn */ +# define YYLTYPE_IS_DECLARED 1 +# define YYLTYPE_IS_TRIVIAL 1 +#endif /* Copy the second part of user declarations. */ + +/* + * Prototypes of internal functions. + */ + +static int LookupWord(YYSTYPE* yylvalPtr, char *buff); + static void TclDateerror(YYLTYPE* location, + DateInfo* info, const char *s); + static int TclDatelex(YYSTYPE* yylvalPtr, YYLTYPE* location, + DateInfo* info); +static time_t ToSeconds(time_t Hours, time_t Minutes, + time_t Seconds, MERIDIAN Meridian); +MODULE_SCOPE int yyparse(DateInfo*); + + + /* Line 216 of yacc.c. */ @@ -466,14 +482,16 @@ void free (void *); /* INFRINGES ON USER NAME SPACE */ #if (! defined yyoverflow \ && (! defined __cplusplus \ - || (defined YYSTYPE_IS_TRIVIAL && YYSTYPE_IS_TRIVIAL))) + || (defined YYLTYPE_IS_TRIVIAL && YYLTYPE_IS_TRIVIAL \ + && defined YYSTYPE_IS_TRIVIAL && YYSTYPE_IS_TRIVIAL))) /* A type that is properly aligned for any stack member. */ union yyalloc { yytype_int16 yyss; YYSTYPE yyvs; - }; + YYLTYPE yyls; +}; /* The size of the maximum gap between one aligned stack and the next. */ # define YYSTACK_GAP_MAXIMUM (sizeof (union yyalloc) - 1) @@ -481,8 +499,8 @@ union yyalloc /* The size of an array large to enough to hold all stacks, each with N elements. */ # define YYSTACK_BYTES(N) \ - ((N) * (sizeof (yytype_int16) + sizeof (YYSTYPE)) \ - + YYSTACK_GAP_MAXIMUM) + ((N) * (sizeof (yytype_int16) + sizeof (YYSTYPE) + sizeof (YYLTYPE)) \ + + 2 * YYSTACK_GAP_MAXIMUM) /* Copy COUNT objects from FROM to TO. The source and destination do not overlap. */ @@ -526,7 +544,7 @@ union yyalloc #define YYLAST 79 /* YYNTOKENS -- Number of terminals. */ -#define YYNTOKENS 27 +#define YYNTOKENS 26 /* YYNNTS -- Number of nonterminals. */ #define YYNNTS 16 /* YYNRULES -- Number of rules. */ @@ -536,7 +554,7 @@ union yyalloc /* YYTRANSLATE(YYLEX) -- Bison symbol number corresponding to YYLEX. */ #define YYUNDEFTOK 2 -#define YYMAXUTOK 275 +#define YYMAXUTOK 274 #define YYTRANSLATE(YYX) \ ((unsigned int) (YYX) <= YYMAXUTOK ? yytranslate[YYX] : YYUNDEFTOK) @@ -548,8 +566,8 @@ static const yytype_uint8 yytranslate[] = 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 26, 23, 22, 25, 24, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 21, 2, + 2, 2, 2, 25, 22, 21, 24, 23, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 20, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, @@ -571,7 +589,7 @@ static const yytype_uint8 yytranslate[] = 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, - 15, 16, 17, 18, 19, 20 + 15, 16, 17, 18, 19 }; #if YYDEBUG @@ -590,35 +608,35 @@ static const yytype_uint8 yyprhs[] = /* YYRHS -- A `-1'-separated list of the rules' RHS. */ static const yytype_int8 yyrhs[] = { - 28, 0, -1, -1, 28, 29, -1, 30, -1, 31, - -1, 33, -1, 34, -1, 32, -1, 37, -1, 35, - -1, 36, -1, 41, -1, 14, 7, -1, 14, 21, - 14, 42, -1, 14, 21, 14, 22, 14, -1, 14, - 21, 14, 21, 14, 42, -1, 14, 21, 14, 21, - 14, 22, 14, -1, 15, 17, -1, 15, -1, 5, - -1, 4, -1, 4, 23, -1, 14, 4, -1, 39, - 14, 4, -1, 20, 4, -1, 14, 24, 14, -1, - 14, 24, 14, 24, 14, -1, 18, -1, 14, 22, - 9, 22, 14, -1, 14, 22, 14, 22, 14, -1, - 9, 14, -1, 9, 14, 23, 14, -1, 14, 9, - -1, 16, -1, 14, 9, 14, -1, 20, 9, -1, - 20, 14, 9, -1, 18, 15, 18, -1, 18, 15, - 14, 21, 14, 21, 14, -1, 18, 18, -1, 11, - 14, 25, 14, -1, 38, 3, -1, 38, -1, 39, - 14, 40, -1, 14, 40, -1, 20, 40, -1, 20, - 14, 40, -1, 40, -1, 22, -1, 26, -1, 12, - -1, 19, -1, 10, -1, 14, -1, -1, 7, -1 + 27, 0, -1, -1, 27, 28, -1, 29, -1, 30, + -1, 32, -1, 33, -1, 31, -1, 36, -1, 34, + -1, 35, -1, 40, -1, 13, 7, -1, 13, 20, + 13, 41, -1, 13, 20, 13, 21, 13, -1, 13, + 20, 13, 20, 13, 41, -1, 13, 20, 13, 20, + 13, 21, 13, -1, 14, 16, -1, 14, -1, 5, + -1, 4, -1, 4, 22, -1, 13, 4, -1, 38, + 13, 4, -1, 19, 4, -1, 13, 23, 13, -1, + 13, 23, 13, 23, 13, -1, 17, -1, 13, 21, + 8, 21, 13, -1, 13, 21, 13, 21, 13, -1, + 8, 13, -1, 8, 13, 22, 13, -1, 13, 8, + -1, 15, -1, 13, 8, 13, -1, 19, 8, -1, + 19, 13, 8, -1, 17, 14, 17, -1, 17, 14, + 13, 20, 13, 20, 13, -1, 17, 17, -1, 10, + 13, 24, 13, -1, 37, 3, -1, 37, -1, 38, + 13, 39, -1, 13, 39, -1, 19, 39, -1, 19, + 13, 39, -1, 39, -1, 21, -1, 25, -1, 11, + -1, 18, -1, 9, -1, 13, -1, -1, 7, -1 }; /* YYRLINE[YYN] -- source line where rule number YYN was defined. */ static const yytype_uint16 yyrline[] = { - 0, 185, 185, 186, 189, 192, 195, 198, 201, 204, - 207, 211, 216, 219, 225, 231, 239, 245, 256, 260, - 264, 270, 274, 278, 282, 286, 292, 296, 301, 306, - 311, 316, 320, 325, 329, 334, 341, 345, 351, 360, - 369, 379, 393, 398, 401, 404, 407, 410, 413, 418, - 421, 426, 430, 434, 440, 458, 461 + 0, 225, 225, 226, 229, 232, 235, 238, 241, 244, + 247, 251, 256, 259, 265, 271, 279, 285, 296, 300, + 304, 310, 314, 318, 322, 326, 332, 336, 341, 346, + 351, 356, 360, 365, 369, 374, 381, 385, 391, 400, + 409, 419, 433, 438, 441, 444, 447, 450, 453, 458, + 461, 466, 470, 474, 480, 498, 501 }; #endif @@ -628,12 +646,12 @@ static const yytype_uint16 yyrline[] = static const char *const yytname[] = { "$end", "error", "$undefined", "tAGO", "tDAY", "tDAYZONE", "tID", - "tMERIDIAN", "tMINUTE_UNIT", "tMONTH", "tMONTH_UNIT", "tSTARDATE", - "tSEC_UNIT", "tSNUMBER", "tUNUMBER", "tZONE", "tEPOCH", "tDST", - "tISOBASE", "tDAY_UNIT", "tNEXT", "':'", "'-'", "','", "'/'", "'.'", - "'+'", "$accept", "spec", "item", "time", "zone", "day", "date", - "ordMonth", "iso", "trek", "relspec", "relunits", "sign", "unit", - "number", "o_merid", 0 + "tMERIDIAN", "tMONTH", "tMONTH_UNIT", "tSTARDATE", "tSEC_UNIT", + "tSNUMBER", "tUNUMBER", "tZONE", "tEPOCH", "tDST", "tISOBASE", + "tDAY_UNIT", "tNEXT", "':'", "'-'", "','", "'/'", "'.'", "'+'", + "$accept", "spec", "item", "time", "zone", "day", "date", "ordMonth", + "iso", "trek", "relspec", "relunits", "sign", "unit", "number", + "o_merid", 0 }; #endif @@ -644,19 +662,19 @@ static const yytype_uint16 yytoknum[] = { 0, 256, 257, 258, 259, 260, 261, 262, 263, 264, 265, 266, 267, 268, 269, 270, 271, 272, 273, 274, - 275, 58, 45, 44, 47, 46, 43 + 58, 45, 44, 47, 46, 43 }; # endif /* YYR1[YYN] -- Symbol number of symbol that rule YYN derives. */ static const yytype_uint8 yyr1[] = { - 0, 27, 28, 28, 29, 29, 29, 29, 29, 29, - 29, 29, 29, 30, 30, 30, 30, 30, 31, 31, - 31, 32, 32, 32, 32, 32, 33, 33, 33, 33, - 33, 33, 33, 33, 33, 33, 34, 34, 35, 35, - 35, 36, 37, 37, 38, 38, 38, 38, 38, 39, - 39, 40, 40, 40, 41, 42, 42 + 0, 26, 27, 27, 28, 28, 28, 28, 28, 28, + 28, 28, 28, 29, 29, 29, 29, 29, 30, 30, + 30, 31, 31, 31, 31, 31, 32, 32, 32, 32, + 32, 32, 32, 32, 32, 32, 33, 33, 34, 34, + 34, 35, 36, 36, 37, 37, 37, 37, 37, 38, + 38, 39, 39, 39, 40, 41, 41 }; /* YYR2[YYN] -- Number of symbols composing right hand side of rule YYN. */ @@ -695,25 +713,25 @@ static const yytype_int8 yydefgoto[] = /* YYPACT[STATE-NUM] -- Index in YYTABLE of the portion describing STATE-NUM. */ -#define YYPACT_NINF -23 +#define YYPACT_NINF -22 static const yytype_int8 yypact[] = { - -23, 2, -23, -22, -23, -5, -23, -4, -23, 22, - -2, -23, 12, -23, 38, -23, -23, -23, -23, -23, - -23, -23, -23, -23, -23, -23, 30, 11, -23, -23, - -23, 17, 10, -23, -23, 35, 40, -6, 47, -23, - -23, 45, -23, -23, -23, 46, -23, -23, 41, 48, - 50, -23, 16, 44, 49, 43, 51, -23, -23, -23, - -23, -23, -23, -23, -23, 54, 55, -23, 56, 59, - 60, 61, -3, -23, -23, -23, -23, 57, 62, -23, - 63, -23, -23 + -22, 2, -22, -21, -22, -4, -22, 1, -22, 22, + 18, -22, 8, -22, 40, -22, -22, -22, -22, -22, + -22, -22, -22, -22, -22, -22, 32, 28, -22, -22, + -22, 24, 26, -22, -22, 42, 47, -5, 49, -22, + -22, 15, -22, -22, -22, 48, -22, -22, 43, 50, + 51, -22, 17, 44, 46, 45, 52, -22, -22, -22, + -22, -22, -22, -22, -22, 56, 57, -22, 58, 60, + 61, 62, -3, -22, -22, -22, -22, 59, 63, -22, + 64, -22, -22 }; /* YYPGOTO[NTERM-NUM]. */ static const yytype_int8 yypgoto[] = { - -23, -23, -23, -23, -23, -23, -23, -23, -23, -23, - -23, -23, -23, -9, -23, 7 + -22, -22, -22, -22, -22, -22, -22, -22, -22, -22, + -22, -22, -22, -9, -22, 6 }; /* YYTABLE[YYPACT[STATE-NUM]]. What to do in state STATE-NUM. If @@ -724,40 +742,40 @@ static const yytype_int8 yypgoto[] = static const yytype_uint8 yytable[] = { 39, 30, 2, 53, 64, 46, 3, 4, 54, 31, - 32, 5, 6, 7, 8, 40, 9, 10, 11, 78, - 12, 13, 14, 64, 15, 48, 33, 41, 16, 34, - 42, 35, 6, 47, 8, 50, 59, 65, 66, 61, - 49, 13, 43, 36, 37, 60, 38, 44, 6, 51, - 8, 6, 45, 8, 52, 58, 6, 13, 8, 56, - 13, 55, 62, 57, 63, 13, 68, 70, 72, 73, - 74, 69, 71, 75, 76, 77, 81, 82, 80, 79 + 5, 6, 7, 8, 32, 9, 10, 11, 78, 12, + 13, 14, 41, 15, 64, 42, 33, 16, 56, 34, + 35, 6, 57, 8, 40, 47, 59, 65, 66, 61, + 13, 48, 36, 37, 43, 38, 49, 60, 44, 6, + 50, 8, 6, 45, 8, 51, 58, 6, 13, 8, + 52, 13, 55, 62, 63, 68, 13, 69, 70, 72, + 73, 74, 71, 75, 76, 77, 81, 82, 79, 80 }; static const yytype_uint8 yycheck[] = { - 9, 23, 0, 9, 7, 14, 4, 5, 14, 14, - 14, 9, 10, 11, 12, 17, 14, 15, 16, 22, - 18, 19, 20, 7, 22, 14, 4, 15, 26, 7, - 18, 9, 10, 3, 12, 25, 45, 21, 22, 48, - 23, 19, 4, 21, 22, 4, 24, 9, 10, 14, - 12, 10, 14, 12, 14, 9, 10, 19, 12, 14, - 19, 14, 14, 18, 14, 19, 22, 24, 14, 14, - 14, 22, 21, 14, 14, 14, 14, 14, 21, 72 + 9, 22, 0, 8, 7, 14, 4, 5, 13, 13, + 8, 9, 10, 11, 13, 13, 14, 15, 21, 17, + 18, 19, 14, 21, 7, 17, 4, 25, 13, 7, + 8, 9, 17, 11, 16, 3, 45, 20, 21, 48, + 18, 13, 20, 21, 4, 23, 22, 4, 8, 9, + 24, 11, 9, 13, 11, 13, 8, 9, 18, 11, + 13, 18, 13, 13, 13, 21, 18, 21, 23, 13, + 13, 13, 20, 13, 13, 13, 13, 13, 72, 20 }; /* YYSTOS[STATE-NUM] -- The (internal number of the) accessing symbol of state STATE-NUM. */ static const yytype_uint8 yystos[] = { - 0, 28, 0, 4, 5, 9, 10, 11, 12, 14, - 15, 16, 18, 19, 20, 22, 26, 29, 30, 31, - 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, - 23, 14, 14, 4, 7, 9, 21, 22, 24, 40, - 17, 15, 18, 4, 9, 14, 40, 3, 14, 23, - 25, 14, 14, 9, 14, 14, 14, 18, 9, 40, - 4, 40, 14, 14, 7, 21, 22, 42, 22, 22, - 24, 21, 14, 14, 14, 14, 14, 14, 22, 42, - 21, 14, 14 + 0, 27, 0, 4, 5, 8, 9, 10, 11, 13, + 14, 15, 17, 18, 19, 21, 25, 28, 29, 30, + 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, + 22, 13, 13, 4, 7, 8, 20, 21, 23, 39, + 16, 14, 17, 4, 8, 13, 39, 3, 13, 22, + 24, 13, 13, 8, 13, 13, 13, 17, 8, 39, + 4, 39, 13, 13, 7, 20, 21, 41, 21, 21, + 23, 20, 13, 13, 13, 13, 13, 13, 21, 41, + 20, 13, 13 }; #define yyerrok (yyerrstatus = 0) @@ -790,7 +808,7 @@ do \ } \ else \ { \ - yyerror (YY_("syntax error: cannot back up")); \ + yyerror (&yylloc, info, YY_("syntax error: cannot back up")); \ YYERROR; \ } \ while (YYID (0)) @@ -845,9 +863,9 @@ while (YYID (0)) /* YYLEX -- calling `yylex' with the right arguments. */ #ifdef YYLEX_PARAM -# define YYLEX yylex (YYLEX_PARAM) +# define YYLEX yylex (&yylval, &yylloc, YYLEX_PARAM) #else -# define YYLEX yylex () +# define YYLEX yylex (&yylval, &yylloc, info) #endif /* Enable debugging if requested. */ @@ -870,7 +888,7 @@ do { \ { \ YYFPRINTF (stderr, "%s ", Title); \ yy_symbol_print (stderr, \ - Type, Value); \ + Type, Value, Location, info); \ YYFPRINTF (stderr, "\n"); \ } \ } while (YYID (0)) @@ -884,17 +902,21 @@ do { \ #if (defined __STDC__ || defined __C99__FUNC__ \ || defined __cplusplus || defined _MSC_VER) static void -yy_symbol_value_print (FILE *yyoutput, int yytype, YYSTYPE const * const yyvaluep) +yy_symbol_value_print (FILE *yyoutput, int yytype, YYSTYPE const * const yyvaluep, YYLTYPE const * const yylocationp, DateInfo* info) #else static void -yy_symbol_value_print (yyoutput, yytype, yyvaluep) +yy_symbol_value_print (yyoutput, yytype, yyvaluep, yylocationp, info) FILE *yyoutput; int yytype; YYSTYPE const * const yyvaluep; + YYLTYPE const * const yylocationp; + DateInfo* info; #endif { if (!yyvaluep) return; + YYUSE (yylocationp); + YYUSE (info); # ifdef YYPRINT if (yytype < YYNTOKENS) YYPRINT (yyoutput, yytoknum[yytype], *yyvaluep); @@ -916,13 +938,15 @@ yy_symbol_value_print (yyoutput, yytype, yyvaluep) #if (defined __STDC__ || defined __C99__FUNC__ \ || defined __cplusplus || defined _MSC_VER) static void -yy_symbol_print (FILE *yyoutput, int yytype, YYSTYPE const * const yyvaluep) +yy_symbol_print (FILE *yyoutput, int yytype, YYSTYPE const * const yyvaluep, YYLTYPE const * const yylocationp, DateInfo* info) #else static void -yy_symbol_print (yyoutput, yytype, yyvaluep) +yy_symbol_print (yyoutput, yytype, yyvaluep, yylocationp, info) FILE *yyoutput; int yytype; YYSTYPE const * const yyvaluep; + YYLTYPE const * const yylocationp; + DateInfo* info; #endif { if (yytype < YYNTOKENS) @@ -930,7 +954,9 @@ yy_symbol_print (yyoutput, yytype, yyvaluep) else YYFPRINTF (yyoutput, "nterm %s (", yytname[yytype]); - yy_symbol_value_print (yyoutput, yytype, yyvaluep); + YY_LOCATION_PRINT (yyoutput, *yylocationp); + YYFPRINTF (yyoutput, ": "); + yy_symbol_value_print (yyoutput, yytype, yyvaluep, yylocationp, info); YYFPRINTF (yyoutput, ")"); } @@ -970,12 +996,14 @@ do { \ #if (defined __STDC__ || defined __C99__FUNC__ \ || defined __cplusplus || defined _MSC_VER) static void -yy_reduce_print (YYSTYPE *yyvsp, int yyrule) +yy_reduce_print (YYSTYPE *yyvsp, YYLTYPE *yylsp, int yyrule, DateInfo* info) #else static void -yy_reduce_print (yyvsp, yyrule) +yy_reduce_print (yyvsp, yylsp, yyrule, info) YYSTYPE *yyvsp; + YYLTYPE *yylsp; int yyrule; + DateInfo* info; #endif { int yynrhs = yyr2[yyrule]; @@ -989,7 +1017,7 @@ yy_reduce_print (yyvsp, yyrule) fprintf (stderr, " $%d = ", yyi + 1); yy_symbol_print (stderr, yyrhs[yyprhs[yyrule] + yyi], &(yyvsp[(yyi + 1) - (yynrhs)]) - ); + , &(yylsp[(yyi + 1) - (yynrhs)]) , info); fprintf (stderr, "\n"); } } @@ -997,7 +1025,7 @@ yy_reduce_print (yyvsp, yyrule) # define YY_REDUCE_PRINT(Rule) \ do { \ if (yydebug) \ - yy_reduce_print (yyvsp, Rule); \ + yy_reduce_print (yyvsp, yylsp, Rule, info); \ } while (YYID (0)) /* Nonzero means print parse trace. It is left uninitialized so that @@ -1248,16 +1276,20 @@ yysyntax_error (char *yyresult, int yystate, int yychar) #if (defined __STDC__ || defined __C99__FUNC__ \ || defined __cplusplus || defined _MSC_VER) static void -yydestruct (const char *yymsg, int yytype, YYSTYPE *yyvaluep) +yydestruct (const char *yymsg, int yytype, YYSTYPE *yyvaluep, YYLTYPE *yylocationp, DateInfo* info) #else static void -yydestruct (yymsg, yytype, yyvaluep) +yydestruct (yymsg, yytype, yyvaluep, yylocationp, info) const char *yymsg; int yytype; YYSTYPE *yyvaluep; + YYLTYPE *yylocationp; + DateInfo* info; #endif { YYUSE (yyvaluep); + YYUSE (yylocationp); + YYUSE (info); if (!yymsg) yymsg = "Deleting"; @@ -1282,7 +1314,7 @@ int yyparse (); #endif #else /* ! YYPARSE_PARAM */ #if defined __STDC__ || defined __cplusplus -int yyparse (void); +int yyparse (DateInfo* info); #else int yyparse (); #endif @@ -1290,14 +1322,6 @@ int yyparse (); -/* The look-ahead symbol. */ -int yychar; - -/* The semantic value of the look-ahead symbol. */ -YYSTYPE yylval; - -/* Number of syntax errors so far. */ -int yynerrs; @@ -1319,15 +1343,25 @@ yyparse (YYPARSE_PARAM) #if (defined __STDC__ || defined __C99__FUNC__ \ || defined __cplusplus || defined _MSC_VER) int -yyparse (void) +yyparse (DateInfo* info) #else int -yyparse () - +yyparse (info) + DateInfo* info; #endif #endif { - + /* The look-ahead symbol. */ +int yychar; + +/* The semantic value of the look-ahead symbol. */ +YYSTYPE yylval; + +/* Number of syntax errors so far. */ +int yynerrs; +/* Location data for the look-ahead symbol. */ +YYLTYPE yylloc; + int yystate; int yyn; int yyresult; @@ -1360,16 +1394,21 @@ yyparse () YYSTYPE *yyvs = yyvsa; YYSTYPE *yyvsp; + /* The location stack. */ + YYLTYPE yylsa[YYINITDEPTH]; + YYLTYPE *yyls = yylsa; + YYLTYPE *yylsp; + /* The locations where the error started and ended. */ + YYLTYPE yyerror_range[2]; - -#define YYPOPSTACK(N) (yyvsp -= (N), yyssp -= (N)) +#define YYPOPSTACK(N) (yyvsp -= (N), yyssp -= (N), yylsp -= (N)) YYSIZE_T yystacksize = YYINITDEPTH; /* The variables used to return semantic value and location from the action routines. */ YYSTYPE yyval; - + YYLTYPE yyloc; /* The number of symbols on the RHS of the reduced rule. Keep to zero when no symbol should be popped. */ @@ -1389,6 +1428,12 @@ yyparse () yyssp = yyss; yyvsp = yyvs; + yylsp = yyls; +#if YYLTYPE_IS_TRIVIAL + /* Initialize the default location before parsing starts. */ + yylloc.first_line = yylloc.last_line = 1; + yylloc.first_column = yylloc.last_column = 0; +#endif goto yysetstate; @@ -1415,7 +1460,7 @@ yyparse () memory. */ YYSTYPE *yyvs1 = yyvs; yytype_int16 *yyss1 = yyss; - + YYLTYPE *yyls1 = yyls; /* Each stack pointer address is followed by the size of the data in use in that stack, in bytes. This used to be a @@ -1424,9 +1469,9 @@ yyparse () yyoverflow (YY_("memory exhausted"), &yyss1, yysize * sizeof (*yyssp), &yyvs1, yysize * sizeof (*yyvsp), - + &yyls1, yysize * sizeof (*yylsp), &yystacksize); - + yyls = yyls1; yyss = yyss1; yyvs = yyvs1; } @@ -1449,7 +1494,7 @@ yyparse () goto yyexhaustedlab; YYSTACK_RELOCATE (yyss); YYSTACK_RELOCATE (yyvs); - + YYSTACK_RELOCATE (yyls); # undef YYSTACK_RELOCATE if (yyss1 != yyssa) YYSTACK_FREE (yyss1); @@ -1459,7 +1504,7 @@ yyparse () yyssp = yyss + yysize - 1; yyvsp = yyvs + yysize - 1; - + yylsp = yyls + yysize - 1; YYDPRINTF ((stderr, "Stack size increased to %lu\n", (unsigned long int) yystacksize)); @@ -1536,7 +1581,7 @@ yybackup: yystate = yyn; *++yyvsp = yylval; - + *++yylsp = yylloc; goto yynewstate; @@ -1567,7 +1612,8 @@ yyreduce: GCC warning that YYVAL may be used uninitialized. */ yyval = yyvsp[1-yylen]; - + /* Default location. */ + YYLLOC_DEFAULT (yyloc, (yylsp - yylen), yylen); YY_REDUCE_PRINT (yyn); switch (yyn) { @@ -2034,7 +2080,7 @@ yyreduce: YY_STACK_PRINT (yyss, yyssp); *++yyvsp = yyval; - + *++yylsp = yyloc; /* Now `shift' the result of the reduction. Determine what state that goes to, based on the state we popped back to and the rule @@ -2060,7 +2106,7 @@ yyerrlab: { ++yynerrs; #if ! YYERROR_VERBOSE - yyerror (YY_("syntax error")); + yyerror (&yylloc, info, YY_("syntax error")); #else { YYSIZE_T yysize = yysyntax_error (0, yystate, yychar); @@ -2084,11 +2130,11 @@ yyerrlab: if (0 < yysize && yysize <= yymsg_alloc) { (void) yysyntax_error (yymsg, yystate, yychar); - yyerror (yymsg); + yyerror (&yylloc, info, yymsg); } else { - yyerror (YY_("syntax error")); + yyerror (&yylloc, info, YY_("syntax error")); if (yysize != 0) goto yyexhaustedlab; } @@ -2096,7 +2142,7 @@ yyerrlab: #endif } - + yyerror_range[0] = yylloc; if (yyerrstatus == 3) { @@ -2112,7 +2158,7 @@ yyerrlab: else { yydestruct ("Error: discarding", - yytoken, &yylval); + yytoken, &yylval, &yylloc, info); yychar = YYEMPTY; } } @@ -2133,6 +2179,7 @@ yyerrorlab: if (/*CONSTCOND*/ 0) goto yyerrorlab; + yyerror_range[0] = yylsp[1-yylen]; /* Do not reclaim the symbols of the rule which action triggered this YYERROR. */ YYPOPSTACK (yylen); @@ -2166,9 +2213,9 @@ yyerrlab1: if (yyssp == yyss) YYABORT; - + yyerror_range[0] = *yylsp; yydestruct ("Error: popping", - yystos[yystate], yyvsp); + yystos[yystate], yyvsp, yylsp, info); YYPOPSTACK (1); yystate = *yyssp; YY_STACK_PRINT (yyss, yyssp); @@ -2179,6 +2226,11 @@ yyerrlab1: *++yyvsp = yylval; + yyerror_range[1] = yylloc; + /* Using YYLLOC is tempting, but would change the location of + the look-ahead. YYLOC is available though. */ + YYLLOC_DEFAULT (yyloc, (yyerror_range - 1), 2); + *++yylsp = yyloc; /* Shift the error token. */ YY_SYMBOL_PRINT ("Shifting", yystos[yyn], yyvsp, yylsp); @@ -2206,7 +2258,7 @@ yyabortlab: | yyexhaustedlab -- memory exhaustion comes here. | `-------------------------------------------------*/ yyexhaustedlab: - yyerror (YY_("memory exhausted")); + yyerror (&yylloc, info, YY_("memory exhausted")); yyresult = 2; /* Fall through. */ #endif @@ -2214,7 +2266,7 @@ yyexhaustedlab: yyreturn: if (yychar != YYEOF && yychar != YYEMPTY) yydestruct ("Cleanup: discarding lookahead", - yytoken, &yylval); + yytoken, &yylval, &yylloc, info); /* Do not reclaim the symbols of the rule which action triggered this YYABORT or YYACCEPT. */ YYPOPSTACK (yylen); @@ -2222,7 +2274,7 @@ yyreturn: while (yyssp != yyss) { yydestruct ("Cleanup: popping", - yystos[*yyssp], yyvsp); + yystos[*yyssp], yyvsp, yylsp, info); YYPOPSTACK (1); } #ifndef yyoverflow @@ -2451,8 +2503,25 @@ static TABLE MilitaryTable[] = { static void TclDateerror( + YYLTYPE* location, + DateInfo* infoPtr, const char *s) { + Tcl_Obj* t; + Tcl_AppendToObj(infoPtr->messages, infoPtr->separatrix, -1); + Tcl_AppendToObj(infoPtr->messages, s, -1); + Tcl_AppendToObj(infoPtr->messages, " (characters ", -1); + t = Tcl_NewIntObj(location->first_column); + Tcl_IncrRefCount(t); + Tcl_AppendObjToObj(infoPtr->messages, t); + Tcl_DecrRefCount(t); + Tcl_AppendToObj(infoPtr->messages, "-", -1); + t = Tcl_NewIntObj(location->last_column); + Tcl_IncrRefCount(t); + Tcl_AppendObjToObj(infoPtr->messages, t); + Tcl_DecrRefCount(t); + Tcl_AppendToObj(infoPtr->messages, ")", -1); + infoPtr->separatrix = "\n"; } static time_t @@ -2487,6 +2556,7 @@ ToSeconds( static int LookupWord( + YYSTYPE* yylvalPtr, char *buff) { register char *p; @@ -2501,11 +2571,11 @@ LookupWord( Tcl_UtfToLower(buff); if (strcmp(buff, "am") == 0 || strcmp(buff, "a.m.") == 0) { - yylval.Meridian = MERam; + yylvalPtr->Meridian = MERam; return tMERIDIAN; } if (strcmp(buff, "pm") == 0 || strcmp(buff, "p.m.") == 0) { - yylval.Meridian = MERpm; + yylvalPtr->Meridian = MERpm; return tMERIDIAN; } @@ -2525,25 +2595,25 @@ LookupWord( for (tp = MonthDayTable; tp->name; tp++) { if (abbrev) { if (strncmp(buff, tp->name, 3) == 0) { - yylval.Number = tp->value; + yylvalPtr->Number = tp->value; return tp->type; } } else if (strcmp(buff, tp->name) == 0) { - yylval.Number = tp->value; + yylvalPtr->Number = tp->value; return tp->type; } } for (tp = TimezoneTable; tp->name; tp++) { if (strcmp(buff, tp->name) == 0) { - yylval.Number = tp->value; + yylvalPtr->Number = tp->value; return tp->type; } } for (tp = UnitsTable; tp->name; tp++) { if (strcmp(buff, tp->name) == 0) { - yylval.Number = tp->value; + yylvalPtr->Number = tp->value; return tp->type; } } @@ -2557,7 +2627,7 @@ LookupWord( buff[i] = '\0'; for (tp = UnitsTable; tp->name; tp++) { if (strcmp(buff, tp->name) == 0) { - yylval.Number = tp->value; + yylvalPtr->Number = tp->value; return tp->type; } } @@ -2565,7 +2635,7 @@ LookupWord( for (tp = OtherTable; tp->name; tp++) { if (strcmp(buff, tp->name) == 0) { - yylval.Number = tp->value; + yylvalPtr->Number = tp->value; return tp->type; } } @@ -2578,7 +2648,7 @@ LookupWord( && isalpha(UCHAR(*buff))) { /* INTL: ISO only */ for (tp = MilitaryTable; tp->name; tp++) { if (strcmp(buff, tp->name) == 0) { - yylval.Number = tp->value; + yylvalPtr->Number = tp->value; return tp->type; } } @@ -2599,7 +2669,7 @@ LookupWord( if (i) { for (tp = TimezoneTable; tp->name; tp++) { if (strcmp(buff, tp->name) == 0) { - yylval.Number = tp->value; + yylvalPtr->Number = tp->value; return tp->type; } } @@ -2610,13 +2680,16 @@ LookupWord( static int TclDatelex( - void *info) + YYSTYPE* yylvalPtr, + YYLTYPE* location, + DateInfo *info) { register char c; register char *p; char buff[20]; int Count; + location->first_column = yyInput - info->dateStart; for ( ; ; ) { while (isspace(UCHAR(*yyInput))) { yyInput++; @@ -2628,9 +2701,9 @@ TclDatelex( */ Count = 0; - for (yylval.Number = 0; + for (yylvalPtr->Number = 0; isdigit(UCHAR(c = *yyInput++)); ) { /* INTL: digit */ - yylval.Number = 10 * yylval.Number + c - '0'; + yylvalPtr->Number = 10 * yylvalPtr->Number + c - '0'; Count++; } yyInput--; @@ -2641,8 +2714,10 @@ TclDatelex( */ if (Count >= 6) { + location->last_column = yyInput - info->dateStart - 1; return tISOBASE; } else { + location->last_column = yyInput - info->dateStart - 1; return tUNUMBER; } } @@ -2655,15 +2730,18 @@ TclDatelex( } *p = '\0'; yyInput--; - return LookupWord(buff); + location->last_column = yyInput - info->dateStart - 1; + return LookupWord(yylvalPtr, buff); } if (c != '(') { + location->last_column = yyInput - info->dateStart; return *yyInput++; } Count = 0; do { c = *yyInput++; if (c == '\0') { + location->last_column = yyInput - info->dateStart - 1; return c; } else if (c == '(') { Count++; @@ -2679,12 +2757,13 @@ TclClockOldscanObjCmd( ClientData clientData, /* Unused */ Tcl_Interp *interp, /* Tcl interpreter */ int objc, /* Count of paraneters */ - Tcl_Obj *const *objv) /* Parameters */ + Tcl_Obj *CONST *objv) /* Parameters */ { Tcl_Obj *result, *resultElement; int yr, mo, da; DateInfo dateInfo; - void *info = (void *) &dateInfo; + DateInfo* info = &dateInfo; + int status; if (objc != 5) { Tcl_WrongNumArgs(interp, 1, objv, @@ -2693,6 +2772,7 @@ TclClockOldscanObjCmd( } yyInput = Tcl_GetString( objv[1] ); + dateInfo.dateStart = yyInput; yyHaveDate = 0; if (Tcl_GetIntFromObj(interp, objv[2], &yr) != TCL_OK @@ -2717,10 +2797,28 @@ TclClockOldscanObjCmd( yyHaveRel = 0; yyRelMonth = 0; yyRelDay = 0; yyRelSeconds = 0; yyRelPointer = NULL; - if (yyparse(info)) { - Tcl_SetObjResult(interp, Tcl_NewStringObj("syntax error", -1)); + dateInfo.messages = Tcl_NewObj(); + dateInfo.separatrix = ""; + Tcl_IncrRefCount(dateInfo.messages); + + status = yyparse(&dateInfo); + if (status == 1) { + Tcl_SetObjResult(interp, dateInfo.messages); + Tcl_DecrRefCount(dateInfo.messages); + return TCL_ERROR; + } else if (status == 2) { + Tcl_SetObjResult(interp, Tcl_NewStringObj("memory exhausted", -1)); + Tcl_DecrRefCount(dateInfo.messages); + return TCL_ERROR; + } else if (status != 0) { + Tcl_SetObjResult(interp, Tcl_NewStringObj("Unknown status returned " + "from date parser. Please " + "report this error as a " + "bug in Tcl.", -1)); + Tcl_DecrRefCount(dateInfo.messages); return TCL_ERROR; } + Tcl_DecrRefCount(dateInfo.messages); if (yyHaveDate > 1) { Tcl_SetObjResult(interp, diff --git a/generic/tclGetDate.y b/generic/tclGetDate.y index 8a7d167..844632e 100644 --- a/generic/tclGetDate.y +++ b/generic/tclGetDate.y @@ -13,9 +13,15 @@ * See the file "license.terms" for information on usage and redistribution of * this file, and for a DISCLAIMER OF ALL WARRANTIES. * - * RCS: @(#) $Id: tclGetDate.y,v 1.40 2009/01/22 06:42:33 nijtmans Exp $ + * RCS: @(#) $Id: tclGetDate.y,v 1.41 2009/06/09 13:52:37 kennykb Exp $ */ +%parse-param {DateInfo* info} +%lex-param {DateInfo* info} +%pure-parser + /* %error-verbose would be nice, but our token names are meaningless */ +%locations + %{ /* * tclDate.c -- @@ -30,7 +36,6 @@ * this file, and for a DISCLAIMER OF ALL WARRANTIES. * */ - #include "tclInt.h" /* @@ -48,6 +53,10 @@ */ typedef struct DateInfo { + + Tcl_Obj* messages; /* Error messages */ + const char* separatrix; /* String separating messages */ + time_t dateYear; time_t dateMonth; time_t dateDay; @@ -75,42 +84,40 @@ typedef struct DateInfo { time_t dateDayNumber; int dateHaveDay; + const char *dateStart; const char *dateInput; time_t *dateRelPointer; int dateDigitCount; } DateInfo; -#define YYPARSE_PARAM info -#define YYLEX_PARAM info - #define YYMALLOC ckalloc #define YYFREE(x) (ckfree((void*) (x))) -#define yyDSTmode (((DateInfo *) info)->dateDSTmode) -#define yyDayOrdinal (((DateInfo *) info)->dateDayOrdinal) -#define yyDayNumber (((DateInfo *) info)->dateDayNumber) -#define yyMonthOrdinal (((DateInfo *) info)->dateMonthOrdinal) -#define yyHaveDate (((DateInfo *) info)->dateHaveDate) -#define yyHaveDay (((DateInfo *) info)->dateHaveDay) -#define yyHaveOrdinalMonth (((DateInfo *) info)->dateHaveOrdinalMonth) -#define yyHaveRel (((DateInfo *) info)->dateHaveRel) -#define yyHaveTime (((DateInfo *) info)->dateHaveTime) -#define yyHaveZone (((DateInfo *) info)->dateHaveZone) -#define yyTimezone (((DateInfo *) info)->dateTimezone) -#define yyDay (((DateInfo *) info)->dateDay) -#define yyMonth (((DateInfo *) info)->dateMonth) -#define yyYear (((DateInfo *) info)->dateYear) -#define yyHour (((DateInfo *) info)->dateHour) -#define yyMinutes (((DateInfo *) info)->dateMinutes) -#define yySeconds (((DateInfo *) info)->dateSeconds) -#define yyMeridian (((DateInfo *) info)->dateMeridian) -#define yyRelMonth (((DateInfo *) info)->dateRelMonth) -#define yyRelDay (((DateInfo *) info)->dateRelDay) -#define yyRelSeconds (((DateInfo *) info)->dateRelSeconds) -#define yyRelPointer (((DateInfo *) info)->dateRelPointer) -#define yyInput (((DateInfo *) info)->dateInput) -#define yyDigitCount (((DateInfo *) info)->dateDigitCount) +#define yyDSTmode (info->dateDSTmode) +#define yyDayOrdinal (info->dateDayOrdinal) +#define yyDayNumber (info->dateDayNumber) +#define yyMonthOrdinal (info->dateMonthOrdinal) +#define yyHaveDate (info->dateHaveDate) +#define yyHaveDay (info->dateHaveDay) +#define yyHaveOrdinalMonth (info->dateHaveOrdinalMonth) +#define yyHaveRel (info->dateHaveRel) +#define yyHaveTime (info->dateHaveTime) +#define yyHaveZone (info->dateHaveZone) +#define yyTimezone (info->dateTimezone) +#define yyDay (info->dateDay) +#define yyMonth (info->dateMonth) +#define yyYear (info->dateYear) +#define yyHour (info->dateHour) +#define yyMinutes (info->dateMinutes) +#define yySeconds (info->dateSeconds) +#define yyMeridian (info->dateMeridian) +#define yyRelMonth (info->dateRelMonth) +#define yyRelDay (info->dateRelDay) +#define yyRelSeconds (info->dateRelSeconds) +#define yyRelPointer (info->dateRelPointer) +#define yyInput (info->dateInput) +#define yyDigitCount (info->dateDigitCount) #define EPOCH 1970 #define START_OF_TIME 1902 @@ -153,32 +160,65 @@ typedef enum _MERIDIAN { MERam, MERpm, MER24 } MERIDIAN; +%} + +%union { + time_t Number; + enum _MERIDIAN Meridian; +} + +%{ + /* * Prototypes of internal functions. */ -static int LookupWord(char *buff); -static void TclDateerror(const char *s); -static int TclDatelex(void *info); +static int LookupWord(YYSTYPE* yylvalPtr, char *buff); + static void TclDateerror(YYLTYPE* location, + DateInfo* info, const char *s); + static int TclDatelex(YYSTYPE* yylvalPtr, YYLTYPE* location, + DateInfo* info); static time_t ToSeconds(time_t Hours, time_t Minutes, time_t Seconds, MERIDIAN Meridian); -MODULE_SCOPE int yyparse(void *); +MODULE_SCOPE int yyparse(DateInfo*); %} -%union { - time_t Number; - enum _MERIDIAN Meridian; -} - -%token tAGO tDAY tDAYZONE tID tMERIDIAN tMINUTE_UNIT tMONTH tMONTH_UNIT -%token tSTARDATE tSEC_UNIT tSNUMBER tUNUMBER tZONE tEPOCH tDST tISOBASE -%token tDAY_UNIT tNEXT - -%type <Number> tDAY tDAYZONE tMINUTE_UNIT tMONTH tMONTH_UNIT tDST -%type <Number> tSEC_UNIT tSNUMBER tUNUMBER tZONE tISOBASE tDAY_UNIT -%type <Number> unit sign tNEXT tSTARDATE -%type <Meridian> tMERIDIAN o_merid +%token tAGO +%token tDAY +%token tDAYZONE +%token tID +%token tMERIDIAN +%token tMONTH +%token tMONTH_UNIT +%token tSTARDATE +%token tSEC_UNIT +%token tSNUMBER +%token tUNUMBER +%token tZONE +%token tEPOCH +%token tDST +%token tISOBASE +%token tDAY_UNIT +%token tNEXT + +%type <Number> tDAY +%type <Number> tDAYZONE +%type <Number> tMONTH +%type <Number> tMONTH_UNIT +%type <Number> tDST +%type <Number> tSEC_UNIT +%type <Number> tSNUMBER +%type <Number> tUNUMBER +%type <Number> tZONE +%type <Number> tISOBASE +%type <Number> tDAY_UNIT +%type <Number> unit +%type <Number> sign +%type <Number> tNEXT +%type <Number> tSTARDATE +%type <Meridian> tMERIDIAN +%type <Meridian> o_merid %% @@ -675,8 +715,25 @@ static TABLE MilitaryTable[] = { static void TclDateerror( + YYLTYPE* location, + DateInfo* infoPtr, const char *s) { + Tcl_Obj* t; + Tcl_AppendToObj(infoPtr->messages, infoPtr->separatrix, -1); + Tcl_AppendToObj(infoPtr->messages, s, -1); + Tcl_AppendToObj(infoPtr->messages, " (characters ", -1); + t = Tcl_NewIntObj(location->first_column); + Tcl_IncrRefCount(t); + Tcl_AppendObjToObj(infoPtr->messages, t); + Tcl_DecrRefCount(t); + Tcl_AppendToObj(infoPtr->messages, "-", -1); + t = Tcl_NewIntObj(location->last_column); + Tcl_IncrRefCount(t); + Tcl_AppendObjToObj(infoPtr->messages, t); + Tcl_DecrRefCount(t); + Tcl_AppendToObj(infoPtr->messages, ")", -1); + infoPtr->separatrix = "\n"; } static time_t @@ -711,6 +768,7 @@ ToSeconds( static int LookupWord( + YYSTYPE* yylvalPtr, char *buff) { register char *p; @@ -725,11 +783,11 @@ LookupWord( Tcl_UtfToLower(buff); if (strcmp(buff, "am") == 0 || strcmp(buff, "a.m.") == 0) { - yylval.Meridian = MERam; + yylvalPtr->Meridian = MERam; return tMERIDIAN; } if (strcmp(buff, "pm") == 0 || strcmp(buff, "p.m.") == 0) { - yylval.Meridian = MERpm; + yylvalPtr->Meridian = MERpm; return tMERIDIAN; } @@ -749,25 +807,25 @@ LookupWord( for (tp = MonthDayTable; tp->name; tp++) { if (abbrev) { if (strncmp(buff, tp->name, 3) == 0) { - yylval.Number = tp->value; + yylvalPtr->Number = tp->value; return tp->type; } } else if (strcmp(buff, tp->name) == 0) { - yylval.Number = tp->value; + yylvalPtr->Number = tp->value; return tp->type; } } for (tp = TimezoneTable; tp->name; tp++) { if (strcmp(buff, tp->name) == 0) { - yylval.Number = tp->value; + yylvalPtr->Number = tp->value; return tp->type; } } for (tp = UnitsTable; tp->name; tp++) { if (strcmp(buff, tp->name) == 0) { - yylval.Number = tp->value; + yylvalPtr->Number = tp->value; return tp->type; } } @@ -781,7 +839,7 @@ LookupWord( buff[i] = '\0'; for (tp = UnitsTable; tp->name; tp++) { if (strcmp(buff, tp->name) == 0) { - yylval.Number = tp->value; + yylvalPtr->Number = tp->value; return tp->type; } } @@ -789,7 +847,7 @@ LookupWord( for (tp = OtherTable; tp->name; tp++) { if (strcmp(buff, tp->name) == 0) { - yylval.Number = tp->value; + yylvalPtr->Number = tp->value; return tp->type; } } @@ -802,7 +860,7 @@ LookupWord( && isalpha(UCHAR(*buff))) { /* INTL: ISO only */ for (tp = MilitaryTable; tp->name; tp++) { if (strcmp(buff, tp->name) == 0) { - yylval.Number = tp->value; + yylvalPtr->Number = tp->value; return tp->type; } } @@ -823,7 +881,7 @@ LookupWord( if (i) { for (tp = TimezoneTable; tp->name; tp++) { if (strcmp(buff, tp->name) == 0) { - yylval.Number = tp->value; + yylvalPtr->Number = tp->value; return tp->type; } } @@ -834,13 +892,16 @@ LookupWord( static int TclDatelex( - void *info) + YYSTYPE* yylvalPtr, + YYLTYPE* location, + DateInfo *info) { register char c; register char *p; char buff[20]; int Count; + location->first_column = yyInput - info->dateStart; for ( ; ; ) { while (isspace(UCHAR(*yyInput))) { yyInput++; @@ -852,9 +913,9 @@ TclDatelex( */ Count = 0; - for (yylval.Number = 0; + for (yylvalPtr->Number = 0; isdigit(UCHAR(c = *yyInput++)); ) { /* INTL: digit */ - yylval.Number = 10 * yylval.Number + c - '0'; + yylvalPtr->Number = 10 * yylvalPtr->Number + c - '0'; Count++; } yyInput--; @@ -865,8 +926,10 @@ TclDatelex( */ if (Count >= 6) { + location->last_column = yyInput - info->dateStart - 1; return tISOBASE; } else { + location->last_column = yyInput - info->dateStart - 1; return tUNUMBER; } } @@ -879,15 +942,18 @@ TclDatelex( } *p = '\0'; yyInput--; - return LookupWord(buff); + location->last_column = yyInput - info->dateStart - 1; + return LookupWord(yylvalPtr, buff); } if (c != '(') { + location->last_column = yyInput - info->dateStart; return *yyInput++; } Count = 0; do { c = *yyInput++; if (c == '\0') { + location->last_column = yyInput - info->dateStart - 1; return c; } else if (c == '(') { Count++; @@ -908,7 +974,8 @@ TclClockOldscanObjCmd( Tcl_Obj *result, *resultElement; int yr, mo, da; DateInfo dateInfo; - void *info = (void *) &dateInfo; + DateInfo* info = &dateInfo; + int status; if (objc != 5) { Tcl_WrongNumArgs(interp, 1, objv, @@ -917,6 +984,7 @@ TclClockOldscanObjCmd( } yyInput = Tcl_GetString( objv[1] ); + dateInfo.dateStart = yyInput; yyHaveDate = 0; if (Tcl_GetIntFromObj(interp, objv[2], &yr) != TCL_OK @@ -941,10 +1009,28 @@ TclClockOldscanObjCmd( yyHaveRel = 0; yyRelMonth = 0; yyRelDay = 0; yyRelSeconds = 0; yyRelPointer = NULL; - if (yyparse(info)) { - Tcl_SetObjResult(interp, Tcl_NewStringObj("syntax error", -1)); + dateInfo.messages = Tcl_NewObj(); + dateInfo.separatrix = ""; + Tcl_IncrRefCount(dateInfo.messages); + + status = yyparse(&dateInfo); + if (status == 1) { + Tcl_SetObjResult(interp, dateInfo.messages); + Tcl_DecrRefCount(dateInfo.messages); + return TCL_ERROR; + } else if (status == 2) { + Tcl_SetObjResult(interp, Tcl_NewStringObj("memory exhausted", -1)); + Tcl_DecrRefCount(dateInfo.messages); + return TCL_ERROR; + } else if (status != 0) { + Tcl_SetObjResult(interp, Tcl_NewStringObj("Unknown status returned " + "from date parser. Please " + "report this error as a " + "bug in Tcl.", -1)); + Tcl_DecrRefCount(dateInfo.messages); return TCL_ERROR; } + Tcl_DecrRefCount(dateInfo.messages); if (yyHaveDate > 1) { Tcl_SetObjResult(interp, diff --git a/library/clock.tcl b/library/clock.tcl index 22b7f67..e76fb13 100644 --- a/library/clock.tcl +++ b/library/clock.tcl @@ -13,7 +13,7 @@ # See the file "license.terms" for information on usage and redistribution # of this file, and for a DISCLAIMER OF ALL WARRANTIES. # -# RCS: @(#) $Id: clock.tcl,v 1.52 2009/01/03 04:26:49 kennykb Exp $ +# RCS: @(#) $Id: clock.tcl,v 1.53 2009/06/09 13:52:38 kennykb Exp $ # #---------------------------------------------------------------------- @@ -1369,7 +1369,7 @@ proc ::tcl::clock::FreeScan { string base timezone locale } { [dict get $date dayOfMonth] } result] if { $status != 0 } { - return -code error "unable to convert date-time string \"$string\"" + return -code error "unable to convert date-time string \"$string\": $result" } lassign $result parseDate parseTime parseZone parseRel \ diff --git a/tests/clock.test b/tests/clock.test index 7eb1b25..0f1e9da 100644 --- a/tests/clock.test +++ b/tests/clock.test @@ -11,7 +11,7 @@ # See the file "license.terms" for information on usage and redistribution # of this file, and for a DISCLAIMER OF ALL WARRANTIES. # -# RCS: @(#) $Id: clock.test,v 1.90 2009/01/03 04:38:12 kennykb Exp $ +# RCS: @(#) $Id: clock.test,v 1.91 2009/06/09 13:52:38 kennykb Exp $ if {[lsearch [namespace children] ::tcltest] == -1} { package require tcltest 2 @@ -35578,9 +35578,12 @@ test clock-33.11a {clock test, millis align with micros} { test clock-34.1 {clock scan tests} { list [catch {clock scan} msg] $msg } {1 {wrong # args: should be "clock scan string ?-base seconds? ?-format string? ?-gmt boolean? ?-locale LOCALE? ?-timezone ZONE?"}} -test clock-34.2 {clock scan tests} { - list [catch {clock scan "bad-string"} msg] $msg -} {1 {unable to convert date-time string "bad-string"}} +test clock-34.2 {clock scan tests} {*}{ + -body {clock scan "bad-string"} + -returnCodes error + -match glob + -result {unable to convert date-time string "bad-string"*} +} test clock-34.3 {clock scan tests} { clock format [clock scan "14 Feb 92" -gmt true] \ -format {%m/%d/%y %I:%M:%S %p} -gmt true @@ -35804,6 +35807,38 @@ test clock-34.47 {ago with multiple relative units} { expr {$base - $res} } 180000 +test clock-34.48 {more than one ToD} {*}{ + -body {clock scan {10:00 11:00}} + -returnCodes error + -result {unable to convert date-time string "10:00 11:00": more than one time of day in string} +} + +test clock-34.49 {more than one date} {*}{ + -body {clock scan {1/1/2001 2/2/2002}} + -returnCodes error + -result {unable to convert date-time string "1/1/2001 2/2/2002": more than one date in string} +} + +test clock-34.50 {more than one time zone} {*}{ + -body {clock scan {10:00 EST CST}} + -returnCodes error + -result {unable to convert date-time string "10:00 EST CST": more than one time zone in string} +} + +test clock-34.51 {more than one weekday} {*}{ + -body {clock scan {Monday Tuesday}} + -returnCodes error + -result {unable to convert date-time string "Monday Tuesday": more than one weekday in string} +} + +test clock-34.52 {more than one ordinal month} {*}{ + -body {clock scan {next January next March}} + -returnCodes error + -result {unable to convert date-time string "next January next March": more than one ordinal month in string} +} + + + # clock seconds test clock-35.1 {clock seconds tests} { expr [clock seconds]+1 |