1 /* Parser for Gedcom dates.
2 Copyright (C) 2001 The Genes Development Team
3 This file is part of the Gedcom parser library.
4 Contributed by Peter Verthez <Peter.Verthez@advalvas.be>, 2001.
6 The Gedcom parser library is free software; you can redistribute it
7 and/or modify it under the terms of the GNU Lesser General Public
8 License as published by the Free Software Foundation; either
9 version 2.1 of the License, or (at your option) any later version.
11 The Gedcom parser library is distributed in the hope that it will be
12 useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 Lesser General Public License for more details.
16 You should have received a copy of the GNU Lesser General Public
17 License along with the Gedcom parser library; if not, write to the
18 Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
29 int _get_day_num(const char* input);
30 int _get_year_num(Year_type ytype, const char* input1, const char* input2);
31 void error_missing_year();
32 void error_missing_month();
38 struct date_value date_val;
42 %token <string> ESC_DATE_GREG
43 %token <string> ESC_DATE_JULN
44 %token <string> ESC_DATE_HEBR
45 %token <string> ESC_DATE_FREN
46 %token <string> MOD_FROM
47 %token <string> MOD_TO
48 %token <string> MOD_BEF
49 %token <string> MOD_AFT
50 %token <string> MOD_BET
51 %token <string> MOD_AND
52 %token <string> MOD_ABT
53 %token <string> MOD_CAL
54 %token <string> MOD_EST
55 %token <string> MOD_INT
56 %token <string> MON_JAN
57 %token <string> MON_FEB
58 %token <string> MON_MAR
59 %token <string> MON_APR
60 %token <string> MON_MAY
61 %token <string> MON_JUN
62 %token <string> MON_JUL
63 %token <string> MON_AUG
64 %token <string> MON_SEP
65 %token <string> MON_OCT
66 %token <string> MON_NOV
67 %token <string> MON_DEC
68 %token <string> MON_TSH
69 %token <string> MON_CSH
70 %token <string> MON_KSL
71 %token <string> MON_TVT
72 %token <string> MON_SHV
73 %token <string> MON_ADR
74 %token <string> MON_ADS
75 %token <string> MON_NSN
76 %token <string> MON_IYR
77 %token <string> MON_SVN
78 %token <string> MON_TMZ
79 %token <string> MON_AAV
80 %token <string> MON_ELL
81 %token <string> MON_VEND
82 %token <string> MON_BRUM
83 %token <string> MON_FRIM
84 %token <string> MON_NIVO
85 %token <string> MON_PLUV
86 %token <string> MON_VENT
87 %token <string> MON_GERM
88 %token <string> MON_FLOR
89 %token <string> MON_PRAI
90 %token <string> MON_MESS
91 %token <string> MON_THER
92 %token <string> MON_FRUC
93 %token <string> MON_COMP
97 %token <string> NUMBER
99 %token <string> BADTOKEN
101 %type <date_val> date_value
102 %type <date_val> date_period
103 %type <date_val> date_range
104 %type <date_val> date_approx
105 %type <date_val> date_interpr
106 %type <string> date_phrase
111 date_value : date { make_date_value(DV_NO_MODIFIER,
112 &$1, &def_date, ""); }
117 | date_phrase { make_date_value(DV_PHRASE,
118 &def_date, &def_date, $1); }
121 /* If empty string: return empty string in 'phrase'
122 member as fallback */
123 /* Note: this can only happen in compatibility mode */
124 make_date_value(DV_PHRASE,
125 &def_date, &def_date, curr_line_value);
127 | error { /* On error: put entire string in 'phrase' member
129 gedcom_date_error(_("Putting date '%s' in 'phrase' member"), curr_line_value);
130 make_date_value(DV_PHRASE,
131 &def_date, &def_date, curr_line_value);
136 date : ESC_DATE_GREG date_greg { copy_date(&$$, &date_s);
137 $$.cal = CAL_GREGORIAN; }
138 | ESC_DATE_JULN date_juln { copy_date(&$$, &date_s);
139 $$.cal = CAL_JULIAN; }
140 | ESC_DATE_HEBR date_hebr { copy_date(&$$, &date_s);
141 $$.cal = CAL_HEBREW; }
142 | ESC_DATE_FREN date_fren { copy_date(&$$, &date_s);
143 $$.cal = CAL_FRENCH_REV; }
144 | date_greg { copy_date(&$$, &date_s);
145 $$.cal = CAL_GREGORIAN; }
148 date_period : MOD_FROM date { make_date_value(DV_FROM,
149 &$2, &def_date, ""); }
150 | MOD_TO date { make_date_value(DV_TO,
151 &$2, &def_date, ""); }
152 | MOD_FROM date { copy_date(&$<date>$, &$2); }
154 { make_date_value(DV_FROM_TO, &$<date>3, &$5, ""); }
157 date_range : MOD_BEF date { make_date_value(DV_BEFORE,
158 &$2, &def_date, ""); }
159 | MOD_AFT date { make_date_value(DV_AFTER,
160 &$2, &def_date, ""); }
161 | MOD_BET date { copy_date(&$<date>$, &$2); }
163 { make_date_value(DV_BETWEEN, &$<date>3, &$5, ""); }
166 date_approx : MOD_ABT date { make_date_value(DV_ABOUT,
167 &$2, &def_date, ""); }
168 | MOD_CAL date { make_date_value(DV_CALCULATED,
169 &$2, &def_date, ""); }
170 | MOD_EST date { make_date_value(DV_ESTIMATED,
171 &$2, &def_date, ""); }
174 date_interpr : MOD_INT date date_phrase
175 { make_date_value(DV_INTERPRETED, &$2, &def_date, $3); }
178 date_phrase : OPEN TEXT CLOSE { $$ = $2; }
181 date_greg : day month_greg year_greg
182 | month_greg year_greg
184 | day month_greg { error_missing_year(); YYERROR; }
185 | month_greg { error_missing_year(); YYERROR; }
186 | day year_greg { error_missing_month(); YYERROR; }
189 date_juln : day month_greg year
192 | day month_greg { error_missing_year(); YYERROR; }
193 | month_greg { error_missing_year(); YYERROR; }
194 | day year_greg { error_missing_month(); YYERROR; }
197 date_hebr : day month_hebr year
200 | day month_hebr { error_missing_year(); YYERROR; }
201 | month_hebr { error_missing_year(); YYERROR; }
202 | day year { error_missing_month(); YYERROR; }
205 date_fren : day month_fren year
208 | day month_hebr { error_missing_year(); YYERROR; }
209 | month_hebr { error_missing_year(); YYERROR; }
210 | day year { error_missing_month(); YYERROR; }
215 int d = _get_day_num($1);
217 strcpy(date_s.day_str, $1);
224 month_greg : MON_JAN { strcpy(date_s.month_str, $1);
226 | MON_FEB { strcpy(date_s.month_str, $1);
228 | MON_MAR { strcpy(date_s.month_str, $1);
230 | MON_APR { strcpy(date_s.month_str, $1);
232 | MON_MAY { strcpy(date_s.month_str, $1);
234 | MON_JUN { strcpy(date_s.month_str, $1);
236 | MON_JUL { strcpy(date_s.month_str, $1);
238 | MON_AUG { strcpy(date_s.month_str, $1);
240 | MON_SEP { strcpy(date_s.month_str, $1);
242 | MON_OCT { strcpy(date_s.month_str, $1);
244 | MON_NOV { strcpy(date_s.month_str, $1);
246 | MON_DEC { strcpy(date_s.month_str, $1);
250 month_hebr : MON_TSH { strcpy(date_s.month_str, $1);
252 | MON_CSH { strcpy(date_s.month_str, $1);
254 | MON_KSL { strcpy(date_s.month_str, $1);
256 | MON_TVT { strcpy(date_s.month_str, $1);
258 | MON_SHV { strcpy(date_s.month_str, $1);
260 | MON_ADR { strcpy(date_s.month_str, $1);
262 | MON_ADS { strcpy(date_s.month_str, $1);
264 | MON_NSN { strcpy(date_s.month_str, $1);
266 | MON_IYR { strcpy(date_s.month_str, $1);
268 | MON_SVN { strcpy(date_s.month_str, $1);
270 | MON_TMZ { strcpy(date_s.month_str, $1);
272 | MON_AAV { strcpy(date_s.month_str, $1);
274 | MON_ELL { strcpy(date_s.month_str, $1);
278 month_fren : MON_VEND { strcpy(date_s.month_str, $1);
280 | MON_BRUM { strcpy(date_s.month_str, $1);
282 | MON_FRIM { strcpy(date_s.month_str, $1);
284 | MON_NIVO { strcpy(date_s.month_str, $1);
286 | MON_PLUV { strcpy(date_s.month_str, $1);
288 | MON_VENT { strcpy(date_s.month_str, $1);
290 | MON_GERM { strcpy(date_s.month_str, $1);
292 | MON_FLOR { strcpy(date_s.month_str, $1);
294 | MON_PRAI { strcpy(date_s.month_str, $1);
296 | MON_MESS { strcpy(date_s.month_str, $1);
298 | MON_THER { strcpy(date_s.month_str, $1);
300 | MON_FRUC { strcpy(date_s.month_str, $1);
302 | MON_COMP { strcpy(date_s.month_str, $1);
307 { int y = _get_year_num(YEAR_SINGLE, $1, NULL);
309 strcpy(date_s.year_str, $1);
311 date_s.year_type = YEAR_SINGLE;
318 { int y = _get_year_num(YEAR_SINGLE, $1, NULL);
320 strcpy(date_s.year_str, $1);
322 date_s.year_type = YEAR_SINGLE;
326 | NUMBER SLASH NUMBER
327 { if (compat_double_date_check($3)) {
328 safe_buf_append(&compat_buffer, "BET %s AND %s",
332 int y = _get_year_num(YEAR_DOUBLE, $1, $3);
334 sprintf(date_s.year_str, "%d/%02d", y-1, y%100);
336 date_s.year_type = YEAR_DOUBLE;
345 void error_missing_year()
347 gedcom_date_error(_("Year is missing: '%s'"),
351 void error_missing_month()
353 gedcom_date_error(_("Month is missing: '%s'"),
357 int _get_day_num(const char* input)
359 if (strlen(input) <= MAX_DAY_LEN)
362 gedcom_date_error(_("Too many characters in day '%s'"), input);
367 int get_day_num(const char* input)
369 int token = get_date_token(input);
371 return _get_day_num(input);
373 gedcom_date_error(_("Not a valid day number: '%s'"), input);
379 { /* CAL_GREGORIAN */ MON_JAN,
380 /* CAL_JULIAN */ MON_JAN,
381 /* CAL_HEBREW */ MON_TSH,
382 /* CAL_FRENCH_REV */ MON_VEND
386 { /* CAL_GREGORIAN */ MON_DEC,
387 /* CAL_JULIAN */ MON_DEC,
388 /* CAL_HEBREW */ MON_ELL,
389 /* CAL_FRENCH_REV */ MON_COMP
392 int get_month_num(Calendar_type cal, const char* input)
394 int token = get_date_token(input);
395 if (token >= begin_month[cal] && token <= end_month[cal])
396 return token - begin_month[cal] + 1;
398 gedcom_date_error(_("Not a valid month for the given calendar: '%s'"),
404 int _get_year_num(Year_type ytype, const char* input1, const char* input2)
406 if (ytype == YEAR_SINGLE) {
407 if (strlen(input1) <= MAX_YEAR_LEN) {
411 gedcom_date_error(_("Too many characters in year '%s'"), input1);
416 if (strlen(input2) != 2) {
417 gedcom_date_error(_("Year after slash should be two digits: '%s/%s'"),
421 if (strlen(input1) <= MAX_YEAR_LEN - 3) {
422 int year1 = atoi(input1) + 1;
423 int year2 = atoi(input2);
424 if (year1 % 100 != year2) {
425 gedcom_date_error(_("Year after slash should be following year: '%s/%s'"),
433 gedcom_date_error(_("Too many characters in year '%s/%s'"),
440 int get_year_num(const char* input, Year_type* ytype)
442 char *year1, *year2 = NULL;
443 int numtok = get_year_tokens(input, &year1, &year2);
445 *ytype = (numtok == 1 ? YEAR_SINGLE : YEAR_DOUBLE);
446 return _get_year_num (*ytype, year1, year2);
449 gedcom_date_error(_("Not a valid year: '%s'"), input);