diff options
-rw-r--r-- | docs/date-examples.txt | 6 | ||||
-rw-r--r-- | parsetime.h | 71 | ||||
-rw-r--r-- | parsetime.yy | 90 | ||||
-rw-r--r-- | scantime.ll | 3 |
4 files changed, 87 insertions, 83 deletions
diff --git a/docs/date-examples.txt b/docs/date-examples.txt index 948d6980..2c2afe94 100644 --- a/docs/date-examples.txt +++ b/docs/date-examples.txt @@ -34,3 +34,9 @@ February 02 February-02 Feb 02, 2002 February 02, 2002 +2002-02-02 12:00:00 +2002-02-02 12:00:00 AM +2002-02-02 12:00 AM +2002-02-02 12:00AM +2002-02-02 12p +2002-02-02 12a diff --git a/parsetime.h b/parsetime.h index 5a9281de..16b969f5 100644 --- a/parsetime.h +++ b/parsetime.h @@ -1,67 +1,6 @@ -/* A Bison parser, made by GNU Bison 2.3. */ - -/* Skeleton interface for Bison's Yacc-like parsers in C - - Copyright (C) 1984, 1989, 1990, 2000, 2001, 2002, 2003, 2004, 2005, 2006 - Free Software Foundation, Inc. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2, or (at your option) - any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street, Fifth Floor, - Boston, MA 02110-1301, USA. */ - -/* As a special exception, you may create a larger work that contains - part or all of the Bison parser skeleton and distribute that work - under terms of your choice, so long as that work isn't itself a - parser generator using the skeleton or a modified version thereof - as a parser skeleton. Alternatively, if you modify or redistribute - the parser skeleton itself, you may (at your option) remove this - special exception, which will cause the skeleton and the resulting - Bison output files to be licensed under the GNU General Public - License without this special exception. - - This special exception was added by the Free Software Foundation in - version 2.2 of Bison. */ - -/* Tokens. */ -#ifndef YYTOKENTYPE -# define YYTOKENTYPE - /* Put the tokens into the symbol table, so that GDB and other debuggers - know about them. */ - enum yytokentype { - TOK_FOURNUM = 258, - TOK_TWONUM = 259, - TOK_ONENUM = 260, - TOK_MONTH = 261, - TOK_SPACE = 262 - }; -#endif -/* Tokens. */ -#define TOK_FOURNUM 258 -#define TOK_TWONUM 259 -#define TOK_ONENUM 260 -#define TOK_MONTH 261 +#define TOK_FOURNUM 257 +#define TOK_TWONUM 258 +#define TOK_ONENUM 259 +#define TOK_MONTH 260 +#define TOK_AMPM 261 #define TOK_SPACE 262 - - - - -#if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED -typedef int YYSTYPE; -# define yystype YYSTYPE /* obsolescent; will be withdrawn */ -# define YYSTYPE_IS_DECLARED 1 -# define YYSTYPE_IS_TRIVIAL 1 -#endif - -extern YYSTYPE yylval; - diff --git a/parsetime.yy b/parsetime.yy index f34730c4..f2b204c9 100644 --- a/parsetime.yy +++ b/parsetime.yy @@ -9,6 +9,8 @@ static struct std::tm * timeval; namespace { boost::posix_time::ptime moment; + struct time_to_leave : std::exception {}; + yyFlexLexer * lexer; inline void yyerror(const char *str) { @@ -23,21 +25,21 @@ namespace { { switch (std::toupper(name[0])) { case 'J': - if (name[1] == std::tolower('a')) + if (std::tolower(name[1]) == 'a') return 1; - else if (name[2] == std::tolower('n')) + else if (std::tolower(name[2]) == 'n') return 6; else return 7; case 'F': return 2; case 'M': - if (name[2] == std::tolower('r')) + if (std::tolower(name[2]) == 'r') return 3; else return 5; case 'A': - if (name[1] == std::tolower('p')) + if (std::tolower(name[1]) == 'p') return 4; else return 8; @@ -76,6 +78,30 @@ namespace { (year.ival < 70 ? year.ival + 100 : year.ival) : year.ival - 1900); } + + void set_hms(const ledger::intorchar& ampm, + const ledger::intorchar& hour, + const ledger::intorchar& min = ledger::intorchar(), + const ledger::intorchar& sec = ledger::intorchar()) + { + if (ampm.sval && std::tolower(ampm.sval[0]) == 'a' && hour.ival == 12) + timeval->tm_hour = 0; + else if (ampm.sval && std::tolower(ampm.sval[0]) == 'p' && hour.ival == 12) + timeval->tm_hour = 12; + else if (hour.ival < 0 || (! ampm.sval && hour.ival > 23) || + (ampm.sval && hour.ival > 12)) + throw ledger::datetime_error("Hour out of range"); + else + timeval->tm_hour += hour.ival; + + if (min.ival < -1 || min.ival > 59) + throw ledger::datetime_error("Minute out of range"); + if (sec.ival < -1 || sec.ival > 59) + throw ledger::datetime_error("Seconds out of range"); + + timeval->tm_min = min.ival == -1 ? 0 : min.ival; + timeval->tm_sec = sec.ival == -1 ? 0 : sec.ival; + } } %} @@ -84,6 +110,7 @@ namespace { %token TOK_TWONUM %token TOK_ONENUM %token TOK_MONTH +%token TOK_AMPM %token TOK_SPACE @@ -91,12 +118,12 @@ namespace { %% -input: date optspace ; - -optspace: /* epsilon */ | TOK_SPACE ; +input: date +{ + throw time_to_leave(); +}; -date: - absdate opttime +date: absdate opttime { if (timeval->tm_gmtoff != -1) { boost::posix_time::ptime::time_duration_type offset; @@ -195,13 +222,39 @@ absdate: } ; -opttime: /* epsilon */ | - TOK_SPACE TOK_TWONUM ':' TOK_TWONUM ':' TOK_TWONUM -{ - timeval->tm_hour = $2.ival; - timeval->tm_min = $4.ival; - timeval->tm_sec = $6.ival; -}; +opttime: /* epsilon */ | TOK_SPACE time ; + +time: + onetwo optspace TOK_AMPM { + if (std::tolower($3.sval[0]) == 'p') + timeval->tm_hour = 12; + else + timeval->tm_hour = 0; + + set_hms($3, $1); + } +| + onetwo ':' TOK_TWONUM optampm { + set_hms($4, $1, $3); + } +| + onetwo ':' TOK_TWONUM ':' TOK_TWONUM optampm { + set_hms($6, $1, $3, $5); + } +; + +onetwo: TOK_ONENUM { $$ = $1; } | TOK_TWONUM { $$ = $1; } ; + +optspace: /* epsilon */ | TOK_SPACE ; + +optampm: /* epsilon */ | + optspace TOK_AMPM { + if (std::tolower($2.sval[0]) == 'p') + timeval->tm_hour = 12; + else + timeval->tm_hour = 0; + $$ = $2; + }; isodate: year TOK_FOURNUM optisotime @@ -250,7 +303,6 @@ boost::posix_time::ptime parse_abs_datetime(std::istream& input) temp.tm_gmtoff = -1; timeval = &temp; - //yydebug = 1; // jww (2007-04-19): Catch any boost errors thrown from here and // push them onto the new error stack scheme. @@ -258,6 +310,9 @@ boost::posix_time::ptime parse_abs_datetime(std::istream& input) if (yyparse() == 0) return moment; } + catch (const time_to_leave&) { + return moment; + } catch (ledger::datetime_error *) { throw; } @@ -275,6 +330,7 @@ namespace ledger { int main() { + yydebug = 1; std::cout << parse_abs_datetime(std::cin) << std::endl; return 0; } diff --git a/scantime.ll b/scantime.ll index 02d00d78..75819bcc 100644 --- a/scantime.ll +++ b/scantime.ll @@ -13,6 +13,7 @@ extern YYSTYPE yylval; shortmon (Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec) longmon (January|February|March|April|May|June|July|August|September|October|November|December) +ampm (AM|PM|am|pm|A.M.|P.M.|a.m.|p.m.|[AP]|[ap]) %% @@ -26,4 +27,6 @@ longmon (January|February|March|April|May|June|July|August|September|October|No {shortmon} yylval = ledger::intorchar(yytext); return TOK_MONTH; {longmon} yylval = ledger::intorchar(yytext); return TOK_MONTH; +{ampm} yylval = ledger::intorchar(yytext); return TOK_AMPM; + . return (int) yytext[0]; |