summaryrefslogtreecommitdiff
path: root/parsetime.yy
diff options
context:
space:
mode:
Diffstat (limited to 'parsetime.yy')
-rw-r--r--parsetime.yy272
1 files changed, 272 insertions, 0 deletions
diff --git a/parsetime.yy b/parsetime.yy
new file mode 100644
index 00000000..ae7ca125
--- /dev/null
+++ b/parsetime.yy
@@ -0,0 +1,272 @@
+%{
+#define YYSTYPE struct ledger::intorchar
+
+#include "times.h"
+#include "FlexLexer.h"
+
+static struct std::tm * timeval;
+
+namespace {
+ boost::posix_time::ptime moment;
+
+ yyFlexLexer * lexer;
+
+ inline void yyerror(const char *str) {
+ throw new ledger::datetime_error(str);
+ }
+
+ inline int yylex(void) {
+ return lexer->yylex();
+ }
+
+ int month_to_int(char * name)
+ {
+ switch (std::toupper(name[0])) {
+ case 'J':
+ if (name[1] == std::tolower('a'))
+ return 1;
+ else if (name[2] == std::tolower('n'))
+ return 6;
+ else
+ return 7;
+ case 'F':
+ return 2;
+ case 'M':
+ if (name[2] == std::tolower('r'))
+ return 3;
+ else
+ return 5;
+ case 'A':
+ if (name[1] == std::tolower('p'))
+ return 4;
+ else
+ return 8;
+ case 'S':
+ return 9;
+ case 'O':
+ return 10;
+ case 'N':
+ return 11;
+ case 'D':
+ return 12;
+ default:
+ std::cerr << "What?? (" << name << ")" << std::endl;
+ assert(0);
+ return -1;
+ }
+ }
+
+ void set_mdy(const ledger::intorchar& month,
+ const ledger::intorchar& day,
+ const ledger::intorchar& year = ledger::intorchar(),
+ bool shortyear = false)
+ {
+ if (ledger::day_before_month) {
+ timeval->tm_mon = (day.ival == -1 ?
+ month_to_int(day.sval) : day.ival) - 1;
+ timeval->tm_mday = month.ival;
+ } else {
+ timeval->tm_mon = (month.ival == -1 ?
+ month_to_int(month.sval) : month.ival) - 1;
+ timeval->tm_mday = day.ival;
+ }
+
+ if (year.ival != -1)
+ timeval->tm_year = (shortyear ?
+ (year.ival < 70 ? year.ival + 100 : year.ival) :
+ year.ival - 1900);
+ }
+}
+
+%}
+
+%token TOK_FOURNUM
+%token TOK_TWONUM
+%token TOK_ONENUM
+%token TOK_MONTH
+
+%token TOK_SPACE
+
+%left '/' '-' '.' 'T'
+
+%%
+
+input: date optspace ;
+
+optspace: /* epsilon */ | TOK_SPACE ;
+
+date: absdate {
+ if (timeval->tm_gmtoff != -1) {
+ boost::posix_time::ptime::time_duration_type offset;
+ offset = boost::posix_time::seconds(timeval->tm_gmtoff);
+ moment = boost::posix_time::from_time_t(timegm(timeval)) - offset;
+ } else {
+ moment = boost::posix_time::ptime_from_tm(*timeval);
+ }
+};
+
+absdate:
+ year '/' morday '/' morday {
+ set_mdy($3, $5, $1);
+ }
+|
+ year '-' morday '-' morday {
+ set_mdy($3, $5, $1);
+ }
+|
+ year '.' morday '.' morday {
+ set_mdy($3, $5, $1);
+ }
+|
+ morday '/' morday '/' year {
+ set_mdy($1, $3, $5);
+ }
+|
+ morday '-' morday '-' year {
+ set_mdy($1, $3, $5);
+ }
+|
+ morday '.' morday '.' year {
+ set_mdy($1, $3, $5);
+ }
+|
+ morday '.' morday {
+ set_mdy($1, $3);
+ }
+|
+ morday '/' morday {
+ set_mdy($1, $3);
+ }
+|
+ morday '-' morday {
+ set_mdy($1, $3);
+ }
+|
+ morday '/' morday '/' TOK_TWONUM {
+ set_mdy($1, $3, $5, true);
+ }
+|
+ morday '-' morday '-' TOK_TWONUM {
+ set_mdy($1, $3, $5, true);
+ }
+|
+ morday '.' morday '.' TOK_TWONUM {
+ set_mdy($1, $3, $5, true);
+ }
+|
+ isodate
+|
+ year TOK_SPACE TOK_MONTH TOK_SPACE morday {
+ set_mdy($3, $5, $1);
+ }
+|
+ morday TOK_SPACE TOK_MONTH TOK_SPACE year {
+ set_mdy($3, $1, $5);
+ }
+|
+ TOK_MONTH TOK_SPACE morday {
+ set_mdy($1, $3);
+ }
+|
+ morday TOK_SPACE TOK_MONTH {
+ set_mdy($3, $1);
+ }
+|
+ year '-' TOK_MONTH '-' morday {
+ set_mdy($3, $5, $1);
+ }
+|
+ morday '-' TOK_MONTH '-' year {
+ set_mdy($3, $1, $5);
+ }
+|
+ TOK_MONTH '-' morday {
+ set_mdy($1, $3);
+ }
+|
+ morday '-' TOK_MONTH {
+ set_mdy($3, $1);
+ }
+|
+ TOK_MONTH TOK_SPACE morday ',' TOK_SPACE year {
+ set_mdy($1, $3, $6);
+ }
+;
+
+isodate:
+ year TOK_FOURNUM opttime
+{
+ timeval->tm_year = $1.ival - 1900;
+ timeval->tm_mon = $2.ival / 100 - 1;
+ timeval->tm_mday = $3.ival % 100;
+};
+
+opttime: /* epsilon */ |
+ 'T' TOK_FOURNUM TOK_TWONUM optzone
+{
+ timeval->tm_hour = $2.ival / 100;
+ timeval->tm_min = $2.ival % 100;
+ timeval->tm_sec = $3.ival;
+};
+
+optzone: /* epsilon */ |
+ '-' TOK_FOURNUM {
+ timeval->tm_gmtoff = - (($2.ival / 100) * 3600 + ($2.ival % 100) * 60);
+ }
+| '+' TOK_FOURNUM {
+ timeval->tm_gmtoff = (($2.ival / 100) * 3600 + ($2.ival % 100) * 60);
+ };
+
+year: TOK_FOURNUM { $$ = $1; };
+
+morday:
+ TOK_TWONUM { $$ = $1; }
+| TOK_ONENUM { $$ = $1; };
+
+%%
+
+int yywrap()
+{
+ return 1;
+}
+
+boost::posix_time::ptime parse_abs_datetime(std::istream& input)
+{
+ lexer = new yyFlexLexer(&input);
+
+ struct std::tm temp;
+ std::memset(&temp, 0, sizeof(struct std::tm));
+ temp.tm_year = 2002 - 1900;
+ 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.
+ try {
+ if (yyparse() == 0)
+ return moment;
+ }
+ catch (ledger::datetime_error *) {
+ throw;
+ }
+ catch (...) {
+ throw new ledger::datetime_error("Failed to parse date/time");
+ }
+ throw new ledger::datetime_error("Failed to parse date/time");
+}
+
+#ifdef MAIN
+
+namespace ledger {
+ bool day_before_month = false;
+}
+
+int main()
+{
+ std::cout << parse_abs_datetime(std::cin) << std::endl;
+ return 0;
+}
+
+#endif // MAIN